137 lines
3.2 KiB
Vue
137 lines
3.2 KiB
Vue
<script lang="ts">
|
||
export default {
|
||
name: "LayTab",
|
||
};
|
||
</script>
|
||
|
||
<script setup lang="ts">
|
||
import "./index.less";
|
||
import tabItem from "../tabItem/index.vue";
|
||
import {
|
||
Component,
|
||
computed,
|
||
useSlots,
|
||
provide,
|
||
VNode,
|
||
Ref,
|
||
ref,
|
||
watch,
|
||
} from "vue";
|
||
|
||
export type tabPositionType = "top" | "bottom" | "left" | "right";
|
||
|
||
export interface LayTabProps {
|
||
type?: string;
|
||
modelValue: string;
|
||
allowClose?: boolean;
|
||
tabPosition?: tabPositionType;
|
||
beforeClose?: Function;
|
||
beforeLeave?: Function;
|
||
}
|
||
|
||
const slot = useSlots();
|
||
const slots = slot.default && slot.default();
|
||
const childrens: Ref<VNode[]> = ref([]);
|
||
const slotsChange = ref(true);
|
||
|
||
const setItemInstanceBySlot = function (nodeList: VNode[]) {
|
||
nodeList?.map((item) => {
|
||
let component = item.type as Component;
|
||
if (component.name != tabItem.name) {
|
||
setItemInstanceBySlot(item.children as VNode[]);
|
||
} else {
|
||
childrens.value.push(item);
|
||
}
|
||
});
|
||
};
|
||
|
||
const props = withDefaults(defineProps<LayTabProps>(), {
|
||
tabPosition: "top",
|
||
});
|
||
|
||
const emit = defineEmits(["update:modelValue", "change", "close"]);
|
||
|
||
const active = computed({
|
||
get() {
|
||
return props.modelValue;
|
||
},
|
||
set(val) {
|
||
emit("update:modelValue", val);
|
||
},
|
||
});
|
||
|
||
const change = function (id: any) {
|
||
// 回调切换标签之前的回调钩子函数,只要不是return false, 则进行切换该tab
|
||
if (props.beforeLeave && props.beforeLeave(id) === false) {
|
||
return;
|
||
}
|
||
emit("update:modelValue", id);
|
||
emit("change", id);
|
||
};
|
||
|
||
const close = function (index: number, id: any) {
|
||
// 回调关闭之前的回调函数,只要不是return false, 则进行关闭该tab
|
||
if (props.beforeClose && props.beforeClose(id) === false) {
|
||
return;
|
||
}
|
||
|
||
// 删除当前tab
|
||
childrens.value.splice(index, 1);
|
||
// 点击的是当前激活的tab,则需要切换到下一个tab
|
||
if (active.value === id) {
|
||
const nextChildren =
|
||
childrens.value[index === childrens.value.length ? 0 : index];
|
||
change(nextChildren && nextChildren.props ? nextChildren.props.id : "");
|
||
}
|
||
emit("close", id);
|
||
};
|
||
|
||
watch(slotsChange, function () {
|
||
childrens.value = [];
|
||
setItemInstanceBySlot((slot.default && slot.default()) as VNode[]);
|
||
});
|
||
|
||
provide("active", active);
|
||
provide("slotsChange", slotsChange);
|
||
</script>
|
||
|
||
<template>
|
||
<div
|
||
class="layui-tab"
|
||
:class="[
|
||
type ? 'layui-tab-' + type : '',
|
||
props.tabPosition ? `is-${tabPosition}` : '',
|
||
]"
|
||
v-if="active"
|
||
>
|
||
<div
|
||
:class="['layui-tab-head', props.tabPosition ? `is-${tabPosition}` : '']"
|
||
>
|
||
<ul
|
||
:class="[
|
||
'layui-tab-title',
|
||
props.tabPosition ? `is-${tabPosition}` : '',
|
||
]"
|
||
>
|
||
<li
|
||
v-for="(children, index) in childrens"
|
||
:key="children"
|
||
:class="[children.props.id === active ? 'layui-this' : '']"
|
||
@click.stop="change(children.props.id)"
|
||
>
|
||
{{ children.props.title }}
|
||
<i
|
||
v-if="allowClose && children.props.closable != false"
|
||
class="layui-icon layui-icon-close layui-unselect layui-tab-close"
|
||
@click.stop="close(index, children.props.id)"
|
||
></i>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="layui-tab-content">
|
||
<slot></slot>
|
||
</div>
|
||
</div>
|
||
</template>
|