前言
新项目 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 弄' }] }
封装过程中遇到的问题和思考
- 整个封装过程使用到的技术点相关内容,主要为
slot 的合理使用
、父子组件的互相传值
、父子组件的事件触发
- 组件封装的内容在我们目前项目的高业务复杂度(包含高度自定义设计出来的功能,以及UI层的特殊需求效果)的项目中,当前业务未开展的情况下,无产品原型,无UI设计规范及效果,纯技术层封装对于业务的支持目前不确定,部分组件在开发过程使用可能需要二次调整和修改。
- 目前前端封装小组已经封装了一多半的 ElementUI 组件,一些组件在封装中发现,部分封装出来的组件在后期更换UI库时不时很灵活,在不调整业务代码的情况下,支持不同的UI库组件切换封装层的代码需要支持两种情况,或基于新的UI库组件用法修改调用参数进行匹配处理,这部分的后期在更新UI库时组件的修改代价还是很高的。
GitHub 源码地址
https://github.com/gywgithub/element2-package
GitHub 仓库预览地址
https://gywgithub.github.io/element2-package