大家在做后盾管理系统的时候,写的最多的可能就是表格页面了,个别分三局部:搜寻功能区、表格内容区和分页器区。个别这些性能都是应用第三方组件库实现,比如说 element-ui
,或者vuetify
。这两个组件库都各有各的长处,但就table
组件来说,我还是比拟喜爱 vuetify
的实现,不必手写一个个 column
,只有传入 headers 的配置数组就行,甚至分页器都内置在了table
组件里,用起来非常不便。有趣味能够看看:vuetify data table。
下面是一个经典的用 element-ui
开发的 table
页面,而且理论工作中如果每个 table
页面都写一遍,反复代码太多了,所以无妨写一个 table
模板组件,缩小反复代码。我的思路是这样的:
-
搜寻功能区:
提供
searchBar
插槽,能够自定义搜寻输入框,搜寻、重置按钮必有,新增按钮通过props
管制显隐。这里对应的代码如下:genSearchBar() {if (this.noSearchBar || !this.$scopedSlots.searchBar) return ''; return (<el-form class="seatch-form" inline={true} label-width="100"> {this.$scopedSlots.searchBar()} <el-button class="filter-item" icon="el-icon-search" type="primary" onClick={this.handleSearchBtnClick} > 查问 </el-button> <el-button class="filter-item" icon="el-icon-refresh" onClick={this.handleResetBtnClick} > 重置 </el-button> <el-button class="filter-item" icon="el-icon-plus" type="primary" v-show={this.showAddBtn} onClick={this.handleAddBtnClick} > 新增 </el-button> </el-form> ); }
-
表格内容区:
通过传入
headers
主动生成columns
,参数如下:{ label: '性别', prop: 'sex', width: '180', filter: 'sexFilter' }
可对应如下代码:
<el-table-column prop="sex" label="性别" width="180"> <template slot-scope="scope">{{scope.row.sex | sexFilter}}</template> </el-table-column>
留神,只反对全局
filter
。如果你想自定义
column
,也提供tableColumn
插槽,反对自定义column
,能够如下配置:{prop: 'action'}
<el-table-column prop="action" label="操作" width="180"> <template slot-scope="scope"> <el-button> 编辑 </el-button> <el-button> 删除 </el-button> </template> </el-table-column>
这样,就会按传入的
prop
匹配对应的column
,非常不便。实现代码如下:
genTableSlot(h) { let customeColumns = this.$scopedSlots.tableColumn ? this.$scopedSlots.tableColumn() : []; return this.headers.map((item) => { // 依据 item.prop 判断是否应用传入的插槽内容 let foundItem = customeColumns.find((ele) => ele.componentOptions && ele.componentOptions.propsData.prop === item.prop ); return foundItem ? foundItem : h('el-table-column', { props: {...item,}, scopedSlots: {default: (props) => { // 依据传入的全局 filter 解决 column 数据 let filter = this.$options.filters[item.filter]; let itemValue = props.row[item.prop]; return h( 'span', filter ? filter(itemValue) : itemValue ); }, }, }); }); }
genTable(h) { return h( 'el-table', { ref: 'tableRef', props: { ...this.$attrs, data: this.data, }, on: {'selection-change': (val) => {this.$emit('selection-change', val); }, }, }, [...this.genTableSlot(h)] ); }
-
分页器区:
如无非凡需要,分页器性能统一,所以间接内置。
实现代码如下:
genPagination() { return ( <div class="pagination-wrap"> <el-pagination layout="total,prev,pager,next,jumper" current-page={this.current} page-size={this.pageSize} total={this.total} {...{on: { 'current-change': this.handleCurrentChange}, }} ></el-pagination> </div> ); }
最初附残缺代码和 demo:
<script> export default { name: 'TableTemplate', props: { data: { type: Array, default: () => [], required: true, }, headers: { type: Array, default: () => [], required: true, }, current: { type: Number, default: 1, }, pageSize: { type: Number, default: 10, }, total: { type: Number, default: 0, }, noSearchBar: Boolean, showAddBtn: Boolean, }, mounted() {this.$nextTick(() => {this.$emit('search'); }); }, methods: {genSearchBar() {if (this.noSearchBar || !this.$scopedSlots.searchBar) return ''; return (<el-form class="seatch-form" inline={true} label-width="100"> {this.$scopedSlots.searchBar()} <el-button class="filter-item" icon="el-icon-search" type="primary" onClick={this.handleSearchBtnClick} > 查问 </el-button> <el-button class="filter-item" icon="el-icon-refresh" onClick={this.handleResetBtnClick} > 重置 </el-button> <el-button class="filter-item" icon="el-icon-plus" type="primary" v-show={this.showAddBtn} onClick={this.handleAddBtnClick} > 新增 </el-button> </el-form> ); }, genTableSlot(h) { let customeColumns = this.$scopedSlots.tableColumn ? this.$scopedSlots.tableColumn() : []; return this.headers.map((item) => { // 依据 item.prop 判断是否应用传入的插槽内容 let foundItem = customeColumns.find((ele) => ele.componentOptions && ele.componentOptions.propsData.prop === item.prop ); return foundItem ? foundItem : h('el-table-column', { props: {...item,}, scopedSlots: {default: (props) => { let filter = this.$options.filters[item.filter]; let itemValue = props.row[item.prop]; return h( 'span', filter ? filter(itemValue) : itemValue ); }, }, }); }); }, genTable(h) { return h( 'el-table', { ref: 'tableRef', props: { ...this.$attrs, data: this.data, }, on: {'selection-change': (val) => {this.$emit('selection-change', val); }, }, }, [...this.genTableSlot(h)] ); }, genPagination() { return ( <div class="pagination-wrap"> <el-pagination layout="total,prev,pager,next,jumper" current-page={this.current} page-size={this.pageSize} total={this.total} {...{on: { 'current-change': this.handleCurrentChange}, }} ></el-pagination> </div> ); }, resetPagination() {this.$emit('update:current', 1); }, handleCurrentChange(val) {this.$emit('update:current', val); this.$emit('search'); }, handleSearchBtnClick() {this.$emit('search'); }, handleResetBtnClick() {this.resetPagination(); this.$emit('reset'); }, handleAddBtnClick() {this.$emit('add'); }, getTableRef() {return this.$refs.tableRef;}, }, render(h) { return ( <div> {this.genSearchBar()} {this.genTable(h)} {this.genPagination()} </div> ); }, }; </script> <style scoped> .seatch-form {text-align: left;} .pagination-wrap { margin-top: 20px; text-align: right; } </style>
Demo:
<template> <div> <table-template border :headers="headers" :data="tableData" :current.sync="current" :total="total" ref="tableTemplate" showAddBtn @search="handleSearch" @reset="handleReset" @add="handleAdd" @selection-change="handleSelectionChange" > <template #searchBar> <el-form-item label="姓名:" prop="title"> <el-input class="filter-item" v-model="searchForm.title" ></el-input> </el-form-item> </template> <template #tableColumn> <el-table-column prop="selection" type="selection" width="55" ></el-table-column> <el-table-column prop="test" label="姓名" width="180"> <template slot-scope="scope"> <el-popover trigger="hover" placement="top"> <p> 姓名:{{scope.row.name}}</p> <p> 住址:{{scope.row.address}}</p> <div slot="reference" class="name-wrapper"> <el-tag size="medium">{{scope.row.name}}</el-tag> </div> </el-popover> </template> </el-table-column> </template> </table-template> </div> </template> <script> import TableTemplate from './TableTemplate'; export default { name: 'Demo', components: {TableTemplate,}, data() { return { current: 1, total: 100, headers: [ {prop: 'selection',}, { label: '姓名', prop: 'name', width: '100', }, { label: '年龄', prop: 'year', }, { label: '性别', prop: 'sex', width: 'sexFilter', }, {prop: 'test',}, ], tableData: [ { name: 'curry', year: 18, sex: 'female', address: '天安门', }, ], searchForm: {title: '',}, }; }, methods: {handleSearch() {console.log(this.current); }, handleReset() { this.searchForm = {title: '',}; }, handleAdd() {console.log('增加'); }, handleSelectionChange(val) {console.log(val); }, getTableRef() {console.log(this.$refs.tableTemplate.getTableRef()); }, }, }; </script>