use-tabs-drag.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import type { Sortable } from '@vben-core/composables';
  2. import type { EmitType } from '@vben-core/typings';
  3. import type { TabsProps } from './types';
  4. import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
  5. import { useIsMobile, useSortable } from '@vben-core/composables';
  6. // 可能会找到拖拽的子元素,这里需要确保拖拽的dom时tab元素
  7. function findParentElement(element: HTMLElement) {
  8. const parentCls = 'group';
  9. return element.classList.contains(parentCls)
  10. ? element
  11. : element.closest(`.${parentCls}`);
  12. }
  13. export function useTabsDrag(props: TabsProps, emit: EmitType) {
  14. const sortableInstance = ref<null | Sortable>(null);
  15. async function initTabsSortable() {
  16. await nextTick();
  17. const el = document.querySelectorAll(
  18. `.${props.contentClass}`,
  19. )?.[0] as HTMLElement;
  20. if (!el) {
  21. console.warn('Element not found for sortable initialization');
  22. return;
  23. }
  24. const resetElState = async () => {
  25. el.style.cursor = 'default';
  26. // el.classList.remove('dragging');
  27. el.querySelector('.draggable')?.classList.remove('dragging');
  28. };
  29. const { initializeSortable } = useSortable(el, {
  30. filter: (_evt, target: HTMLElement) => {
  31. const parent = findParentElement(target);
  32. const draggable = parent?.classList.contains('draggable');
  33. return !draggable || !props.draggable;
  34. },
  35. onEnd(evt) {
  36. const { newIndex, oldIndex } = evt;
  37. // const fromElement = evt.item;
  38. const { srcElement } = (evt as any).originalEvent;
  39. if (!srcElement) {
  40. resetElState();
  41. return;
  42. }
  43. const srcParent = findParentElement(srcElement);
  44. if (!srcParent) {
  45. resetElState();
  46. return;
  47. }
  48. if (!srcParent.classList.contains('draggable')) {
  49. resetElState();
  50. return;
  51. }
  52. if (
  53. oldIndex !== undefined &&
  54. newIndex !== undefined &&
  55. !Number.isNaN(oldIndex) &&
  56. !Number.isNaN(newIndex) &&
  57. oldIndex !== newIndex
  58. ) {
  59. emit('sortTabs', oldIndex, newIndex);
  60. }
  61. resetElState();
  62. },
  63. onMove(evt) {
  64. const parent = findParentElement(evt.related);
  65. if (parent?.classList.contains('draggable') && props.draggable) {
  66. const isCurrentAffix = evt.dragged.classList.contains('affix-tab');
  67. const isRelatedAffix = evt.related.classList.contains('affix-tab');
  68. // 不允许在固定的tab和非固定的tab之间互相拖拽
  69. return isCurrentAffix === isRelatedAffix;
  70. } else {
  71. return false;
  72. }
  73. },
  74. onStart: () => {
  75. el.style.cursor = 'grabbing';
  76. el.querySelector('.draggable')?.classList.add('dragging');
  77. // el.classList.add('dragging');
  78. },
  79. });
  80. sortableInstance.value = await initializeSortable();
  81. }
  82. async function init() {
  83. const { isMobile } = useIsMobile();
  84. // 移动端下tab不需要拖拽
  85. if (isMobile.value) {
  86. return;
  87. }
  88. await nextTick();
  89. initTabsSortable();
  90. }
  91. onMounted(init);
  92. watch(
  93. () => props.styleType,
  94. () => {
  95. sortableInstance.value?.destroy();
  96. init();
  97. },
  98. );
  99. onUnmounted(() => {
  100. sortableInstance.value?.destroy();
  101. });
  102. }