美文网首页vue
Element Table 业务封装与思考

Element Table 业务封装与思考

作者: 草帽lufei | 来源:发表于2022-04-13 17:55 被阅读0次

    前言

    新项目 Elemnet UI 组件业务封装,封装需求满足后期不修改业务代码,直接更新前端的封装组件的UI库代码即可实现无缝切换UI库的需求。目前新项目的功能产品还在梳理,项目第一期还未开始,前端技术小组先行进行的组件封装。

    Table 组件封装目标

    • 封装的用法要和 Element UI Table 组件的用法保持一致
      • 目的是降低引用(使用)成本
    • 支持纯数据绑定
    • 支持自定义模板满足业务定制化需求

    Table 组件封装内容

    目录结构

    components  封装组件目录
      talbe
        Index.vue
        TableColumn.vue
        
    Views
      CenterPage.vue 组件调用层
    
    table/Index.vue

    这个文件默认封装了 el-table 组件外层,里面使用 v-bind="$attrs":xxx="config.xxx" 模式,在 el-table 内层使用 slot 来接受,这样可以满足表格的自定义模板需求,如果只是渲染基本数据,可以直接把 el-table-column 也封装好,如代码中的注释部分

    <template>
      <div>
          <!-- v-model="config.value" -->
        <el-table
          v-bind="$attrs"
          :height="config.height"
          :max-height="config.maxHeight"
          :stripe="config.stripe"
          :border="config.border"
          :size="config.size"
          :fit="config.fit"
          :show-header="config.showHeader"
          :highlight-current-row="config.highlightCurrentRow"
          :row-class-name="config.rowClassName"
          :row-style="config.rowStyle"
          :cell-class-name="config.cellClassName"
          :cell-style="config.cellStyle"
          :header-row-class-name="config.headerRowClassName"
          :header-row-style="config.headerRowStyle"
          :header-cell-class-name="config.headerCellClassName"
          :header-cell-style="config.headerCellStyle"
          :row-key="config.rowKey"
          :empty-text="config.emptyText"
          :default-expand-all="config.defaultExpandAll"
          :expand-row-keys="config.expandRowKeys"
          :default-sort="config.defaultSort"
          :tooltip-effect="config.tooltipEffect"
          :show-summary="config.showSummary"
          :sum-text="config.sumText"
          :summary-method="config.summaryMethod"
          :span-method="config.spanMethod"
          :select-on-indeterminate="config.selectOnIndeterminate"
          :indent="config.indent"
          :lazy="config.lazy"
          :load="config.load"
          :tree-props="config.treeProps"
          v-on="$listeners"
        >
          <slot></slot>
          <!-- <template v-for="(v, i) in config.columns" >
            <el-table-column v-if="!v.slot" :key="i" :prop="v.prop" :label="v.label" :width="v.width">
            </el-table-column>
            <el-table-column v-else :key="i" :prop="v.prop" :label="v.label" :width="v.width">
              <slot></slot>
            </el-table-column>
          </template> -->
        </el-table>
      </div>
    </template>
    
    <script>
    export default {
      name: 'Table',
      props: {
        content: {
          type: String,
          default: ''
        },
        config: {
          type: Object,
          default: () => { }
        }
      }
    }
    </script>
    
    table/TableColumn.vue

    这个文件封装的 el-table-column , 这里面同样了用了 slot 主要用于支持表格列中的自定义部分,添加了一个自定义的参数 isNativeRenter ,表示当前列配置是否是原生数据绑定渲染

    <template>
      <!-- v-model="config.value" -->
      <el-table-column
        v-bind="$attrs"
        :type="config.type"
        :index="config.index"
        :column-key="config.columnKey"
        :label="config.label"
        :prop="config.prop"
        :width="config.width"
        :min-width="config.minWidth"
        :fixed="config.fixed"
        :render-header="config.renderHeader"
        :sortable="config.sortable"
        :sort-method="config.sortMethod"
        :sort-by="config.sortBy"
        :sort-orders="config.sortOrders"
        :resizable="config.resizeable"
        :formatter="config.formatter"
        :show-overflow-tooltip="config.showOverflowTooltip"
        :align="config.align"
        :header-align="config.headerAlign"
        :class-name="config.className"
        :label-class-name="config.labelClassName"
        :selectable="config.selectable"
        :reserve-selection="config.reserveSelection"
        :filters="config.filters"
        :filter-placement="config.filterPlacement"
        :filter-multiple="config.filterMultiple"
        :filter-method="config.filterMethod"
        :filtered-value="config.filteredValue"
        v-on="$listeners"
      >
        <template slot-scope="{ row, column, $index }">
          <slot :nativeData="[row, column, $index]" name="custom"></slot>
          <span v-if="!config.isNativeRenter">{{ row[column.property] }}</span>
        </template>
        <template slot="header">
          <slot name="header"></slot>
        </template>
      </el-table-column>
    </template>
    
    <script>
    export default {
      name: 'TableColumn',
      props: {
        content: {
          type: String,
          default: ''
        },
        config: {
          type: Object,
          default: () => { }
        }
      }
    }
    </script>
    
    

    注意

    这里面的 <template><el-table-column> 的层级结构中间不能有任何其他元素,否则会影响表格列数据的正常排序。如下代码就不可取

    <template>
      <div>
        <el-table-column></el-table-column>
      </div>
    </template>
    
    CenterPage.vue

    基础表格调用,只渲染数据

    template

    <table :config="table.config" :data="table.data">
      <table-column :config="table.config.columns[0]"></table-column>
      <table-column :config="table.config.columns[1]"></table-column>
      <table-column :config="table.config.columns[2]"></table-column>
    </table>
    

    script

     table: {
        config: {
          columns: [
            {
              prop: 'date',
              label: '日期'
            },
            {
              prop: 'name',
              label: '姓名'
            },
            {
              prop: 'address',
              label: '地址'
              width: 300
            }
          ]
        },
        data: [{
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        }, {
          date: '2016-05-04',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1517 弄'
        }, {
          date: '2016-05-01',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1519 弄'
        }, {
          date: '2016-05-03',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1516 弄'
        }]
        },
    

    自定义列模板表格

    <c-table :config="table3.config" :data="table2.data">
      <table-column :config="table3.config.columns[0]">
        <template slot="custom" slot-scope="{ nativeData }">
          <span style="margin-left: 10px">{{ nativeData[2] }}</span>
        </template>
      </table-column>
    
      <table-column :config="table3.config.columns[1]">
        <template slot="custom" slot-scope="{ nativeData }">
          <i class="el-icon-time"></i>
          <span style="margin-left: 10px">{{ nativeData[0].date }}</span>
        </template>
      </table-column>
      <table-column :config="table3.config.columns[2]"></table-column>
      <table-column :config="table3.config.columns[3]"> </table-column>
      <table-column :config="table3.config.columns[4]">
        <template slot="custom" slot-scope="{ nativeData }">
          <el-button
            @click="handleSelectClick(nativeData)"
            type="primary"
            size="small"
            >查看</el-button
          >
          <el-button type="danger" size="small">删除</el-button>
        </template>
      </table-column>
    </c-table>
    

    数据层

    table3: {
      config: {
        columns: [
          {
            width: '50',
            type: 'index'
          },
          {
            prop: 'date',
            label: '日期',
            width: '200',
            key: 'date',
            sortable: true,
            isNativeRenter: true
          },
          {
            prop: 'name',
            label: '姓名',
            key: 'name',
            sortable: true
          },
          {
            prop: 'address',
            label: '地址',
            width: '400',
            key: 'address'
          },
          {
            label: '操作',
            width: '200',
            fixed: 'right',
          }
        ],
        border: true,
        stripe: true,
        size: 'mini'
      },
      data: [{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1518 弄'
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1517 弄'
      }, {
        date: '2016-05-01',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1519 弄'
      }, {
        date: '2016-05-03',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1516 弄'
      }]
    }
    

    封装过程中遇到的问题和思考

    1. 整个封装过程使用到的技术点相关内容,主要为 slot 的合理使用父子组件的互相传值父子组件的事件触发

    2. 组件封装的内容在我们目前项目的高业务复杂度(包含高度自定义设计出来的功能,以及UI层的特殊需求效果)的项目中,当前业务未开展的情况下,无产品原型,无UI设计规范及效果,纯技术层封装对于业务的支持目前不确定,部分组件在开发过程使用可能需要二次调整和修改。

    3. 目前前端封装小组已经封装了一多半的 ElementUI 组件,一些组件在封装中发现,部分封装出来的组件在后期更换UI库时不时很灵活,在不调整业务代码的情况下,支持不同的UI库组件切换封装层的代码需要支持两种情况,或基于新的UI库组件用法修改调用参数进行匹配处理,这部分的后期在更新UI库时组件的修改代价还是很高的。

    GitHub 源码地址

    https://github.com/gywgithub/element2-package

    GitHub 仓库预览地址

    https://gywgithub.github.io/element2-package

    相关文章

      网友评论

        本文标题:Element Table 业务封装与思考

        本文链接:https://www.haomeiwen.com/subject/nfiasrtx.html