2024-05-25 14:10:21 +00:00
|
|
|
|
<script setup lang="ts">
|
2024-07-30 13:05:03 +00:00
|
|
|
|
import type { Sortable } from '@vben-core/composables';
|
2024-07-14 08:28:56 +00:00
|
|
|
|
import type { TabDefinition } from '@vben-core/typings';
|
2024-05-25 14:10:21 +00:00
|
|
|
|
|
2024-08-05 13:12:22 +00:00
|
|
|
|
import type { TabsProps } from './types';
|
|
|
|
|
|
2024-07-30 16:19:17 +00:00
|
|
|
|
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
|
2024-07-14 07:18:02 +00:00
|
|
|
|
|
2024-07-30 13:05:03 +00:00
|
|
|
|
import { useForwardPropsEmits, useSortable } from '@vben-core/composables';
|
2024-05-25 14:10:21 +00:00
|
|
|
|
|
2024-07-14 10:32:37 +00:00
|
|
|
|
import { Tabs, TabsChrome } from './components';
|
2024-05-25 14:10:21 +00:00
|
|
|
|
|
|
|
|
|
interface Props extends TabsProps {}
|
|
|
|
|
|
|
|
|
|
defineOptions({
|
|
|
|
|
name: 'TabsView',
|
|
|
|
|
});
|
|
|
|
|
|
2024-07-14 07:18:02 +00:00
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
|
|
|
contentClass: 'vben-tabs-content',
|
|
|
|
|
dragable: true,
|
2024-07-14 10:32:37 +00:00
|
|
|
|
styleType: 'chrome',
|
2024-07-14 07:18:02 +00:00
|
|
|
|
});
|
2024-05-25 14:10:21 +00:00
|
|
|
|
|
2024-07-14 07:18:02 +00:00
|
|
|
|
const emit = defineEmits<{
|
|
|
|
|
close: [string];
|
|
|
|
|
sortTabs: [number, number];
|
2024-07-14 08:28:56 +00:00
|
|
|
|
unpin: [TabDefinition];
|
2024-07-14 07:18:02 +00:00
|
|
|
|
}>();
|
2024-05-25 14:10:21 +00:00
|
|
|
|
|
|
|
|
|
const forward = useForwardPropsEmits(props, emit);
|
2024-07-14 07:18:02 +00:00
|
|
|
|
|
2024-07-22 16:03:59 +00:00
|
|
|
|
const sortableInstance = ref<null | Sortable>(null);
|
2024-07-14 10:32:37 +00:00
|
|
|
|
|
2024-07-14 07:18:02 +00:00
|
|
|
|
// 可能会找到拖拽的子元素,这里需要确保拖拽的dom时tab元素
|
2024-07-14 10:32:37 +00:00
|
|
|
|
function findParentElement(element: HTMLElement) {
|
2024-07-14 07:18:02 +00:00
|
|
|
|
const parentCls = 'group';
|
|
|
|
|
return element.classList.contains(parentCls)
|
|
|
|
|
? element
|
|
|
|
|
: element.closest(`.${parentCls}`);
|
2024-07-14 10:32:37 +00:00
|
|
|
|
}
|
2024-07-14 07:18:02 +00:00
|
|
|
|
|
|
|
|
|
async function initTabsSortable() {
|
|
|
|
|
await nextTick();
|
|
|
|
|
const { contentClass } = props;
|
|
|
|
|
|
|
|
|
|
const el = document.querySelectorAll(`.${contentClass}`)?.[0] as HTMLElement;
|
|
|
|
|
|
2024-07-28 16:19:26 +00:00
|
|
|
|
const resetElState = () => {
|
|
|
|
|
el.style.cursor = 'default';
|
|
|
|
|
el.classList.remove('dragging');
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-14 07:18:02 +00:00
|
|
|
|
const { initializeSortable } = useSortable(el, {
|
|
|
|
|
filter: (_evt, target: HTMLElement) => {
|
|
|
|
|
const parent = findParentElement(target);
|
|
|
|
|
const dragable = parent?.classList.contains('dragable');
|
|
|
|
|
return !dragable || !props.dragable;
|
|
|
|
|
},
|
|
|
|
|
onEnd(evt) {
|
|
|
|
|
const { newIndex, oldIndex } = evt;
|
|
|
|
|
// const fromElement = evt.item;
|
|
|
|
|
const { srcElement } = (evt as any).originalEvent;
|
|
|
|
|
|
|
|
|
|
if (!srcElement) {
|
2024-07-28 16:19:26 +00:00
|
|
|
|
resetElState();
|
2024-07-14 07:18:02 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const srcParent = findParentElement(srcElement);
|
|
|
|
|
|
|
|
|
|
if (!srcParent) {
|
2024-07-28 16:19:26 +00:00
|
|
|
|
resetElState();
|
2024-07-14 07:18:02 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!srcParent.classList.contains('dragable')) {
|
2024-07-28 16:19:26 +00:00
|
|
|
|
resetElState();
|
|
|
|
|
|
2024-07-14 07:18:02 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
oldIndex !== undefined &&
|
|
|
|
|
newIndex !== undefined &&
|
|
|
|
|
!Number.isNaN(oldIndex) &&
|
|
|
|
|
!Number.isNaN(newIndex) &&
|
|
|
|
|
oldIndex !== newIndex
|
|
|
|
|
) {
|
|
|
|
|
emit('sortTabs', oldIndex, newIndex);
|
|
|
|
|
}
|
2024-07-28 16:19:26 +00:00
|
|
|
|
resetElState();
|
2024-07-14 07:18:02 +00:00
|
|
|
|
},
|
|
|
|
|
onMove(evt) {
|
|
|
|
|
const parent = findParentElement(evt.related);
|
2024-07-14 10:32:37 +00:00
|
|
|
|
return parent?.classList.contains('dragable') && props.dragable;
|
2024-07-14 07:18:02 +00:00
|
|
|
|
},
|
|
|
|
|
onStart: () => {
|
|
|
|
|
el.style.cursor = 'grabbing';
|
|
|
|
|
el.classList.add('dragging');
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2024-07-14 10:32:37 +00:00
|
|
|
|
sortableInstance.value = await initializeSortable();
|
2024-07-14 07:18:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onMounted(initTabsSortable);
|
2024-07-14 10:32:37 +00:00
|
|
|
|
|
2024-07-30 16:19:17 +00:00
|
|
|
|
watch(
|
|
|
|
|
() => props.styleType,
|
|
|
|
|
() => {
|
|
|
|
|
sortableInstance.value?.destroy();
|
|
|
|
|
initTabsSortable();
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-14 10:32:37 +00:00
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
sortableInstance.value?.destroy();
|
|
|
|
|
});
|
2024-05-25 14:10:21 +00:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
2024-07-14 10:32:37 +00:00
|
|
|
|
<TabsChrome v-if="styleType === 'chrome'" v-bind="forward" />
|
|
|
|
|
<Tabs v-else v-bind="forward" />
|
2024-05-25 14:10:21 +00:00
|
|
|
|
</template>
|