如何实现一个element-ui的table

2,304 阅读1分钟

前言

我们日常开发中,经常会用到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是一个比较强大的组件库,利用空闲的时间,了解一点点源码的内容,还是会有收获,最后,大家一家加油学习~