web component原生插槽不支持作用域插槽,vue3也无法拓展web component作用域插槽
我们来举个例子看看作用域插槽和普通写法的区别: 例如树形控件如果要自定义节点显示内容
<el-tree
style="max-width: 600px"
:data="dataSource"
show-checkbox
node-key="id"
default-expand-all
:expand-on-click-node="false"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<span>{{ node.label }}</span>
<span>
<a @click="append(data)"> Append </a>
<a style="margin-left: 8px" @click="remove(node, data)"> Delete </a>
</span>
</span>
</template>
</el-tree>
使用UI5(web component)
<ui5-tree>
<ui5-tree-item expanded text="Tree 1" icon="paste" selected>
<ui5-tree-item expanded text="Tree 1.1" selected>
<ui5-tree-item text="Tree 1.1.1"></ui5-tree-item>
<ui5-tree-item text="Tree 1.1.2"></ui5-tree-item>
</ui5-tree-item>
</ui5-tree-item>
<ui5-tree-item text="Tree 2" icon="copy">
<ui5-tree-item text="Tree 2.1">
<ui5-tree-item text="Tree 2.1.1"></ui5-tree-item>
<ui5-tree-item text="Tree 2.1.2">
<ui5-tree-item text="Tree 2.1.2.1"></ui5-tree-item>
<ui5-tree-item text="Tree 2.1.2.2"></ui5-tree-item>
</ui5-tree-item>
</ui5-tree-item>
<ui5-tree-item text="Tree 2.2"></ui5-tree-item>
</ui5-tree-item>
<ui5-tree-item expanded text="Tree 3 (no icon)"></ui5-tree-item>
</ui5-tree>
通过上面两个例子我们可以看出,vue的作用域插槽是可以作用域所有节点的,而web component不支持作用域插槽只能使用嵌套的写法
要解决这个问题,可以在web component的基础上再根据对应框架再包装一层,比如根据fl-tree封装vue3组件fl-tree-v3
<template>
<fl-tree-item
v-for="node in props.dataList"
:key="node.id"
:node="node"
>
<div slot="label" v-if="slots.default">
<slot v-bind="{node}"></slot>
</div>
<fl-tree-v3
:dataList="node.children || []"
>
<template #default="{ node }">
<slot v-bind="{node}"></slot>
</template>
</fl-tree-v3>
</fl-tree-item>
</template>
<script lang="ts">
export default defineComponent({
name: 'FlTreeV3',
});
</script>
<script lang="ts" setup>
import '../tree-item';
import { defineComponent, useSlots } from 'vue';
const props = defineProps({
dataList: {
type: Array,
required: true
},
});
const slots = useSlots();
</script>
这样在vue3项目中就可以使用fl-tree-v3(vue3组件)来支持作用域插槽的用法了
<fl-tree-v3
:dataList="treeData"
>
<template #default="{ node }">
<span>
{{ node.label }}
<span style="color: red;">(已离职)</span>
</span>
</template>
</fl-tree-v3>
同理,如果你要在vue2项目或者react项目中使用,要用对应的框架实现一遍