tabs-view.vue 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. <script setup lang="ts">
  2. import type { Sortable } from '@vben-core/hooks';
  3. import type { TabDefinition } from '@vben-core/typings';
  4. import { nextTick, onMounted, onUnmounted, ref } from 'vue';
  5. import { useForwardPropsEmits, useSortable } from '@vben-core/hooks';
  6. import { Tabs, TabsChrome } from './components';
  7. import { TabsProps } from './types';
  8. interface Props extends TabsProps {}
  9. defineOptions({
  10. name: 'TabsView',
  11. });
  12. const props = withDefaults(defineProps<Props>(), {
  13. contentClass: 'vben-tabs-content',
  14. dragable: true,
  15. styleType: 'chrome',
  16. });
  17. const emit = defineEmits<{
  18. close: [string];
  19. sortTabs: [number, number];
  20. unpin: [TabDefinition];
  21. }>();
  22. const forward = useForwardPropsEmits(props, emit);
  23. const sortableInstance = ref<Sortable | null>(null);
  24. // 可能会找到拖拽的子元素,这里需要确保拖拽的dom时tab元素
  25. function findParentElement(element: HTMLElement) {
  26. const parentCls = 'group';
  27. return element.classList.contains(parentCls)
  28. ? element
  29. : element.closest(`.${parentCls}`);
  30. }
  31. async function initTabsSortable() {
  32. await nextTick();
  33. const { contentClass } = props;
  34. const el = document.querySelectorAll(`.${contentClass}`)?.[0] as HTMLElement;
  35. const { initializeSortable } = useSortable(el, {
  36. filter: (_evt, target: HTMLElement) => {
  37. const parent = findParentElement(target);
  38. const dragable = parent?.classList.contains('dragable');
  39. return !dragable || !props.dragable;
  40. },
  41. onEnd(evt) {
  42. const { newIndex, oldIndex } = evt;
  43. // const fromElement = evt.item;
  44. const { srcElement } = (evt as any).originalEvent;
  45. if (!srcElement) {
  46. return;
  47. }
  48. const srcParent = findParentElement(srcElement);
  49. if (!srcParent) {
  50. return;
  51. }
  52. if (!srcParent.classList.contains('dragable')) {
  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. el.classList.remove('dragging');
  65. el.style.cursor = 'default';
  66. },
  67. onMove(evt) {
  68. const parent = findParentElement(evt.related);
  69. return parent?.classList.contains('dragable') && props.dragable;
  70. },
  71. onStart: () => {
  72. el.style.cursor = 'grabbing';
  73. el.classList.add('dragging');
  74. },
  75. });
  76. sortableInstance.value = await initializeSortable();
  77. }
  78. onMounted(initTabsSortable);
  79. onUnmounted(() => {
  80. sortableInstance.value?.destroy();
  81. });
  82. </script>
  83. <template>
  84. <TabsChrome v-if="styleType === 'chrome'" v-bind="forward" />
  85. <Tabs v-else v-bind="forward" />
  86. </template>