需求:
????????在开发中需要一个公共组件Tree(树),接受的数据是典型的树结构数据,当前项数据是? ? ? ?一个对象,如果有子节点,拥有一个children属性。我并不希望每一项的数据展现形式是定死的,而是通过插槽能够自定义。
假设:
<template>
<ul class="tree-wrapper">
<li v-for="(item, index) in list" :key="index" @click.stop="change(item)">
<div class="content" :class="{ active: item.active }">
<slot :row="item">{{ item.name }}</slot>
</div>
<Tree :list="item.children" @change="change">
<slot :row="item">{{ item.name }}</slot>
</Tree>
</li>
</ul>
</template>
<script>
export default {
name: 'Tree',
props: {
list: {
type: Array,
default: () => [],
},
},
methods: {
change(item) {
if (!item.active) {
this.$emit('change', item);
}
},
},
};
</script>
<template>
<div class="blog-type-wrapper" v-loading="isLoading">
<Tree :list="typeList" @change="handleChange('categoryID', $event)">
<template #default="{ row }">
<span class="name">{{ row.name }}</span>
<span class="num">{{ row.articleCount }}篇</span>
</template>
</Tree>
</div>
</template>
问题:
? ? ? ? 在组件内部可以通过定义name标识组件,然后使用name名称作为组件名称,实现递归调用,但是递归引用处的插槽内容如何通过外部定义呢?递归内部的数据又如何传递呢?
?解决:
? ? ? ? 使用模板的形式不是很好处理此问题,使用render函数替代模板可以很好的解决
<script>
export default {
render(h) {
//c2函数用于处理动态的插槽部分
const c2 = (item) => {
const arr = [
h(
'div',
{
class: {
content: true, //静态类名
active: item.active, //动态类名
},
},
this.$scopedSlots.default
? this.$scopedSlots.default({ row: item }) //相当于作用域插槽
: item.name //相当于插槽默认值
),
];
//如果存在子级,使用递归处理
if (item.children && item.children.length > 0) {
arr.push(c1(item.children));
}
return arr;
};
//c1函数用于处理固定结构部分(例如ul为父级,每个数据项对应一个li子级)
const c1 = (list) => {
const lis = list.map((item, index) => {
return h(
'li',
{
attrs: {
key: index, //key标识
},
on: {
click: (event) => {
event.stopPropagation(); //阻止事件冒泡,为了精确处理每一项子级的事件
if (!item.active) {
this.$emit('change', item);
}
},
},
},
c2(item)
);
});
const ul = h(
'ul',
{
class: {
'tree-wrapper': true,
},
},
lis
);
return ul;
};
return c1(this.$attrs.list);
},
};
</script>
|