5.原生插槽不支持作用域插槽?看我如何二次封装!

79 阅读1分钟

web component原生插槽不支持作用域插槽,vue3也无法拓展web component作用域插槽

我们来举个例子看看作用域插槽和普通写法的区别: 例如树形控件如果要自定义节点显示内容

使用Element Plus的Tree

<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项目中使用,要用对应的框架实现一遍