这涉及到 Vue 组件的父子通信机制,主要有以下几个关键点:
- 插槽收集过程:
// table.vue 中有一个隐藏的 slot 容器
<div class="hidden-columns" ref="hiddenColumns"><slot></slot></div>
这个隐藏的 div 用来收集所有的 table-column 组件。
- 列注册机制:
// table-column.js 中的 mounted 钩子
mounted() {
const owner = this.owner;
const parent = this.columnOrTableParent;
const children = this.isSubColumn ? parent.$el.children : parent.$refs.hiddenColumns.children;
const columnIndex = this.getColumnElIndex(children, this.$el);
owner.store.commit('insertColumn', this.columnConfig, columnIndex, this.isSubColumn ? parent.columnConfig : null);
}
- 列配置收集:
// table-column.js created 钩子中
created() {
// ...
const column = this.getPropsData(basicProps, sortProps, selectProps, filterProps);
column = mergeOptions(defaults, column);
// 设置列的渲染方式
const chains = compose(this.setColumnRenders, this.setColumnWidth, this.setColumnForcedProps);
column = chains(column);
this.columnConfig = column;
}
工作流程是这样的:
-
当我们写
<table><table-column prop="name" /></table>时:- table 组件会先渲染,创建一个数据中心 store
- table-column 组件会被放入 table 的隐藏 slot 中
-
在 table-column 组件挂载时:
- 它会找到父级 table 组件(通过 owner 计算属性)
- 收集自己的配置信息(prop、label 等属性)
- 通过 store.commit('insertColumn') 把列的配置信息注册到 table 的 store 中
-
table 组件拿到这些列配置后:
- 会根据配置生成表格的列
- 使用这些配置来渲染表头和单元格内容
-
当 table-column 组件销毁时:
destroyed() {
if (!this.$parent) return;
const parent = this.$parent;
this.owner.store.commit('removeColumn', this.columnConfig, this.isSubColumn ? parent.columnConfig : null);
}
会自动从 store 中移除对应的列配置。
这种设计的优点是:
- 声明式的写法,使用起来直观
- 配置分离,每个 table-column 管理自己的配置
- 可以动态增删列
- 支持嵌套表头(通过 isSubColumn 判断)
所以虽然写法上看起来是嵌套的 HTML 结构,但实际上 table-column 并不是在真正渲染表格,它只是一个配置的载体,用来向 table 组件注册列的配置信息。真正的表格渲染是由 table 组件统一管理的。