vue

Element Table 业务封装与思考

2022-04-13  本文已影响0人  草帽lufei

前言

新项目 Elemnet UI 组件业务封装,封装需求满足后期不修改业务代码,直接更新前端的封装组件的UI库代码即可实现无缝切换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

上一篇下一篇

猜你喜欢

热点阅读