use-tabs-drag.ts 2.9 KB

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