为什么可以在el-table中使用el-table-column来渲染表格字段?

275 阅读1分钟

这涉及到 Vue 组件的父子通信机制,主要有以下几个关键点:

  1. 插槽收集过程:
// table.vue 中有一个隐藏的 slot 容器
<div class="hidden-columns" ref="hiddenColumns"><slot></slot></div>

这个隐藏的 div 用来收集所有的 table-column 组件。

  1. 列注册机制:
// 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);
}
  1. 列配置收集:
// 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;
}

工作流程是这样的:

  1. 当我们写 <table><table-column prop="name" /></table> 时:

    • table 组件会先渲染,创建一个数据中心 store
    • table-column 组件会被放入 table 的隐藏 slot 中
  2. 在 table-column 组件挂载时:

    • 它会找到父级 table 组件(通过 owner 计算属性)
    • 收集自己的配置信息(prop、label 等属性)
    • 通过 store.commit('insertColumn') 把列的配置信息注册到 table 的 store 中
  3. table 组件拿到这些列配置后:

    • 会根据配置生成表格的列
    • 使用这些配置来渲染表头和单元格内容
  4. 当 table-column 组件销毁时:

destroyed() {
  if (!this.$parent) return;
  const parent = this.$parent;
  this.owner.store.commit('removeColumn', this.columnConfig, this.isSubColumn ? parent.columnConfig : null);
}

会自动从 store 中移除对应的列配置。

这种设计的优点是:

  1. 声明式的写法,使用起来直观
  2. 配置分离,每个 table-column 管理自己的配置
  3. 可以动态增删列
  4. 支持嵌套表头(通过 isSubColumn 判断)

所以虽然写法上看起来是嵌套的 HTML 结构,但实际上 table-column 并不是在真正渲染表格,它只是一个配置的载体,用来向 table 组件注册列的配置信息。真正的表格渲染是由 table 组件统一管理的。