在递归组件中,根组件的写的slot,递归生成的组件无法渲染。经过研究后可采用子组件递归获取根组件,并对应渲染slot达到预期效果。
组件结构
//调用组件的index.vue
<LeeTable>
<template #date="{ row }"></template>
<template #date2="{ row }"></template>
<LeeTable>
//leeTable main.vue
<el-table>
<template v-for="(column, columnIndex) in (columns)">
//递归组件 Column
<Column :column="column"></Column>
</template>
</el-tbale>
//递归组件Column
<el-table-column>
<!-- 多级表头递归组件 -->
<template v-if="hasSub" #default="scope">
<Column :column="subColumn" v-for="subColumn in column.childs" childs>
</Column>
</template>
<!-- 没有childs -->
<template v-if="isDefault" #default="scope">
<template v-if="column.slotName">
//...渲染模版 渲染slots 见下文
</template>
//...业务代码
</template>
</el-table-column>
获取根组件方法
//tool.ts
import { ComponentInternalInstance } from 'vue'
const rootComponentName = 'LeeTable' //根节点Name
/**
* @description 获取根节点
* @param {ComponentInternalInstance} component 当前节点
* @returns 根节点
*/
export const getRootComponent = (component: ComponentInternalInstance | null): ComponentInternalInstance | null => {
//若当前节点已是根节点 则直接返回当前节点
if (component && component.type.name === rootComponentName) {
return component
}
//当前节点有节点 递归查询 找到根节点
if (component && component.parent) {
const parent = component.parent
return getRootComponent(parent)
}
}
渲染模板
//templateSlot.vue
import { h } from "vue";
export default {
functional: true,
props: {
template: {
type: Function,
},
data: {
type: Object,
},
},
render: (props: any, ctx: any) => {
return h("div", [props.template(props.data)]);
},
}
使用并渲染
//递归组件Column
<el-table-column>
<!-- 多级表头递归组件 -->
<template v-if="hasSub" #default="scope">
<Column :column="subColumn" v-for="subColumn in column.childs" childs>
</Column>
</template>
<!-- 没有childs -->
<template v-if="isDefault" #default="scope">
<template v-if="column.slotName">
//使用渲染模板渲染slot
<templateSlot v-if="nodeTemplate" :template="nodeTemplate" :data="scope" :row="scope.row">
</templateSlot>
</template>
//...业务代码
</template>
</el-table-column>
//递归组件Column.vue
<script lang="ts" setup>
import { getRootComponent } from "./tool";
import { computed, getCurrentInstance, h } from "vue";
import TemplateSlot from "./templateSlot";
//获取根节点
const leeTable = getRootComponent(getCurrentInstance());
//根节点slots
const parentSlots = leeTable?.slots;
//获取当前列对应slots
const nodeTemplate = parentSlots[column.slotName] as any;
</script>