(component): [tabitem] 新增 icon 属性

This commit is contained in:
sight 2022-09-17 23:50:39 +08:00
parent 993d657cf3
commit e1a41552c5
5 changed files with 64 additions and 46 deletions

View File

@ -14,10 +14,7 @@ export default (): UserConfigExport => {
},
],
},
plugins: [
vue(),
vueJsx(),
],
plugins: [vue(), vueJsx()],
build: {
cssCodeSplit: false,
outDir: "lib",

View File

@ -26,6 +26,7 @@ import {
h,
createTextVNode,
isVNode,
Fragment,
} from "vue";
import { useResizeObserver } from "@vueuse/core";
import { TabData, TabInjectKey } from "./interface";
@ -44,7 +45,6 @@ export interface LayTabProps {
const slot = useSlots();
const childrens: Ref<VNode[]> = ref([]);
const slotsChange = ref(true);
const tabMap = reactive(new Map<number, TabData>());
const setItemInstanceBySlot = function (nodeList: VNode[]) {
@ -266,16 +266,27 @@ const update = () => {
}
};
const renderTabChild = (child: TabData) => {
if (child.slots?.title) {
return () => h("span", child.slots?.title && child.slots.title());
const renderTabIcon = (attrs: Record<string, unknown>) => {
const tab = attrs.tabData as TabData;
if (typeof tab.icon === "function") {
return tab.icon();
} else if (typeof tab.icon === "string") {
return h(LayIcon, {
type: tab.icon,
style: "margin-right: 8px;",
});
}
};
if (typeof child.title === "function") {
// @ts-ignore
return () => child.title();
} else if (typeof child.title === "string") {
return () => createTextVNode(child.title as string);
const renderTabTitle = (attrs: Record<string, unknown>) => {
const tab = attrs.tabData as TabData;
if (tab.slots?.title) {
return h(Fragment, tab.slots?.title && tab.slots.title());
}
if (typeof tab.title === "function") {
return tab.title();
} else if (typeof tab.title === "string") {
return createTextVNode(tab.title as string);
}
};
@ -309,7 +320,6 @@ onMounted(() => {
});
provide("active", active);
provide("slotsChange", slotsChange);
</script>
<template>
@ -339,16 +349,23 @@ provide("slotsChange", slotsChange);
:style="tabBarStyle"
></div>
<li
v-for="(children, index) in tabItems"
:key="children.id"
:class="[children.id === active ? 'layui-this' : '']"
@click.stop="change(children.id)"
v-for="(child, index) in tabItems"
:key="child.id"
:class="[child.id === active ? 'layui-this' : '']"
@click.stop="change(child.id)"
>
<RenderFunction :renderFunc="renderTabChild(children)" />
<span>
<RenderFunction
v-if="child['icon']"
:renderFunc="renderTabIcon"
:tabData="child"
/>
<RenderFunction :renderFunc="renderTabTitle" :tabData="child" />
</span>
<i
v-if="allowClose && children.closable != false"
v-if="allowClose && child.closable != false"
class="layui-icon layui-icon-close layui-unselect layui-tab-close"
@click.stop="close(index, children.id)"
@click.stop="close(index, child.id)"
></i>
</li>
</ul>

View File

@ -5,6 +5,7 @@ export const TabInjectKey = Symbol("layuiTab");
export interface TabData {
id: string;
title?: string | Function;
icon?: string | Function;
closable?: string | boolean;
slots: Slots;
}

View File

@ -21,6 +21,7 @@ import { TabInjectKey, TabsContext } from "../tab/interface";
export interface LayTabItemProps {
id: string;
title?: string | Function;
icon?: string | Function;
closable?: boolean | string;
}
@ -31,13 +32,12 @@ const props = withDefaults(defineProps<LayTabItemProps>(), {
const instance = getCurrentInstance();
const slots = useSlots();
const active = inject("active");
const slotsChange: Ref<boolean> = inject("slotsChange") as Ref<boolean>;
slotsChange.value = !slotsChange.value;
const tabsCtx = inject<Partial<TabsContext>>(TabInjectKey, {});
const data = reactive({
id: props.id,
title: props.title,
icon: props.icon,
closable: props.closable,
slots: slots,
});

View File

@ -36,63 +36,65 @@ export default {
:::
::: title 标题插槽
::: title
:::
::: demo 通过 `allow-close` 属性, 启用选项可关闭
::: demo 通过 `icon` 属性, 快速设置前置图标, 也可通过 title 插槽实现
<template>
<lay-tab v-model="current11" :allow-close="true">
<lay-tab-item id="1">
<template #title>
<lay-icon type="layui-icon-console"></lay-icon>
<span style="margin-left:10px">选项一</span>
</template>
<lay-tab-item id="1" title="选项一">
<div style="padding:20px">选项一</div>
</lay-tab-item>
<lay-tab-item id="2">
<template #title>
<lay-icon type="layui-icon-user"></lay-icon>
<span style="margin-left:10px">选项二</span>
</template>
<lay-tab-item id="2" title="选项二" icon="layui-icon-console">
<div style="padding:20px">选项二</div>
</lay-tab-item>
<lay-tab-item id="3">
<template #title>
<lay-icon type="layui-icon-set"></lay-icon>
<span style="margin-left:10px">选项三</span>
</template>
<lay-tab-item id="3" title="选项三" :icon="renderIconFunc">
<div style="padding:20px">选项三</div>
</lay-tab-item>
<lay-tab-item id="4" :title="renderTitleFunc">
<lay-tab-item id="4">
<template #title>
选项四
<lay-icon type="layui-icon-set" style="margin-left:8px"></lay-icon>
</template>
<div style="padding:20px">选项四</div>
</lay-tab-item>
<lay-tab-item id="5" :title="renderTitleFunc">
<div style="padding:20px">选项五</div>
</lay-tab-item>
</lay-tab>
</template>
<script>
import { ref,h , resolveComponent} from 'vue'
import { ref,h , Fragment,resolveComponent} from 'vue'
export default {
setup() {
const LayIcon = resolveComponent("LayIcon");
const current11 = ref("1")
const renderIconFunc = () => h("span", {
style: "margin-right: 8px;"
},"🚧");
const renderTitleFunc = () => [
h(LayIcon,
{
type: "layui-icon-component",
style: "margin-right: 8px;",
}),
h("span",
{
style: "margin-left: 10px; color: red",
style: "color: red",
},
"选项四")
"选项五"),
]
return {
current11,
renderTitleFunc
renderTitleFunc,
renderIconFunc,
}
}
}
@ -418,7 +420,8 @@ export default {
| 属性 | 描述 | 类型 | 默认值 | 可选值 |
| -------- | --------------------- | ---------------- | ------- | -------------- |
| id | 唯一标识 | `string` | - | - |
| title | 头部标题,支持渲染函数 | `string` `vnode` | - | - |
| title | 头部标题 | `string` `VNode` | - | - |
| icon | 前置图标| `string` `VNode`
| closable | 允许关闭 | `boolean` | `false` | `true` `false` |
:::