前言
我们日常开发中,经常会用到table的组件,今天来了解一下它的具体实现,其实还是不一样的。哈哈,今天还用了不一样的主题,才发现。
用法
接下来,我们来看一段非常熟悉的表格的用法。其实为了区分,就把el换成了my;然后我们就来实现一下my-table和my-table-column的组件。
<my-table :data="tableData" style="width: 100%">
<my-table-column prop="name" label="姓名"></my-table-column>
<my-table-column prop="date" label="日期"></my-table-column>
<my-table-column prop="address" label="地址"></my-table-column>
<my-table-column prop="opreation" label="操作">
<span slot-scope="scope">{{ scope.row.name }}</span>
</my-table-column>
</my-table>
实现
由于element-ui的table组件的源码太过复杂。只是为了粗略的了解一下原理,现在来实现一个demo版。
思路
- 渲染表格是先挂载my-table-column组件,再挂载my-table组件。
- 每次创建my-table-column组件时,需要将表头信息全部保存下来,并创建一个渲染表格每一项数据的方法,若表头函数插槽内容存在,将数据通过作用域插槽传递到外层
- 最后在my-table组件,渲染table表格
代码实现
my-table-column组件
<script>
import { store } from "./index";
export default {
props: ["prop", "label"],
created() {
// 设置表头信息
let item = {
prop: this.prop,
label: this.label,
};
item.renderCell = (data) => {
let children = null;
// 表头是否有默认插槽内容
if (this.$scopedSlots.default) {
// 含有内容,使用作用域插槽的方式,将每一行的数据传到外面
// 等效于<slot :row="data.row"></slot>
children = this.$scopedSlots.default(data);
} else {
// 根据表头的属性,数组某一项的键对应的值
const { row, column } = data;
children = row[column.prop];
}
return <div>{children}</div>;
};
store.columns.push(item);
},
render(h) {
return h("div", this.$slots.default);
// return <td>12</td>;
},
};
</script>
store实例
import Vue from 'vue'
// 非常粗暴的用一个vue实例,存储表头信息在全局中
const data = {
columns: [],
}
const store = new Vue({
data: data
})
export {
store
}
my-table组件
<script>
import { store } from "./index";
export default {
props: {
// 传入的数据源
data: {
type: Array,
default: () => {
return [];
},
},
},
created() {
store.columns.length = 0;
},
render() {
// 使用jsx语法
return (
<div>
{/* my-table-column默认插槽的内容,默认隐藏掉不显示 */}
<div style={{ display: "none" }}>{this.$slots.default}</div>
<table cellspacing="0" cellpadding="0">
{/* 表头的渲染,遍历存储表头的数组渲染 */}
<thead>
<tr>
{store.columns.map((item) => (
<th>{item.label}</th>
))}
</tr>
</thead>
{/* 表格内容渲染,
1.首选遍历传入的data数据源,
2.再根据表头中存储的方法,渲染每一个td的内容
3.如果表头中插槽有定义,就渲染插槽的内容
*/}
<tbody>
{this.data.map((item) => {
return (
<tr>
{store.columns.map((column) => {
const columnData = { ...column };
const data = {
column: columnData,
row: item,
};
return <td>{column.renderCell(data)}</td>;
})}
</tr>
);
})}
</tbody>
</table>
</div>
);
},
};
</script>
最后
发现element-ui是一个比较强大的组件库,利用空闲的时间,了解一点点源码的内容,还是会有收获,最后,大家一家加油学习~