When we do the background management system, the most written may be the form page, generally divided into three parts: search function area, table content area and pager area. Typically these functions are implemented using third-party component libraries, such as Element-UI, or Vuetify. Both libraries have their own advantages, but as for the table component, I prefer Vuetify’s implementation. Instead of writing each column by hand, I just pass in the headers configuration array. Even the pagers are built into the table component, making it very easy to use. Check out: Vuetify Data Table.

The above is a classic table page developed with Element-UI, and in practice, if you write every table page once, there is too much code repetition, so you might as well write a table template component to reduce the duplication of code. My thinking goes like this:

  1. Search Ribbon:

    SearchBar provides a slot that allows you to customize the search input box, search and reset buttons must be used, and new buttons must be shown and hidden through props control. The corresponding code here is as follows:

    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} > query < / el - button > < El-button class="filter-item" icon=" El-icon Refresh "onClick={this.handleresetbtnClick} > reset </ El-button > < El-button Class ="filter-item" icon="el-icon-plus" type="primary" v-show={this. showAddBTN} onClick={this. handleadDbTnClick} > new </el-button> </el-form> ); }
  2. Form content area:

    Columns are automatically generated by passing HEADERS with the following parameters:

    {label: 'sex', prop: 'sex', width: '180', filter: 'sexFilter'}

    It can correspond to the following code:

    < el - table - column prop = "sex" label = "gender" width = "180" > < template slot - scope = "scope" > {{scope. Row. Sex | sexFilter}}</template> </el-table-column>

    Note that only global filters are supported.

    If you want to customize Column and also provide a TableColumn slot to support custom Column, you can configure it as follows:

    {
        prop: 'action'
    }
    <el-table-column prop="action" label=" operation "width="180"> <template slot-scope="scope"> <el-button> edit </el-button> <el-button> </el-button> </template> </el-table-column>

    In this way, the passed prop matches the corresponding column, which is convenient.

    The implementation code is as follows:

    genTableSlot(h) { let customeColumns = this.$scopedSlots.tableColumn ? this.$scopedSlots.tableColumn() : []; Return this.headers. Map (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)] ); }
  3. Pager area:

    If no special requirements, the pager function consistent, so direct built-in.

    The implementation code is as follows:

    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> ); }

    Finally, complete code and demo are attached:

    <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} > query < / el - button > < El-button class="filter-item" icon=" El-icon Refresh "onClick={this.handleresetbtnClick} > reset </ El-button > < El-button Class ="filter-item" icon="el-icon-plus" type="primary" v-show={this. showAddBTN} onClick={this. handleadDbTnClick} > new </el-button> </el-form> ); }, genTableSlot(h) { let customeColumns = this.$scopedSlots.tableColumn ? this.$scopedSlots.tableColumn() : []; Return this.headers. Map (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" bb0 <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=" name "width="180"> <template slot-scope="scope"> <el-popover trigger="hover" Placement = "top" > < p > name: {{scope. Row. The name}} < / p > < p > address: {{ 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:' name ', prop: 'name', width: '100',}, {label: 'age, prop:' year '}, {label: }, {prop: 'test',},], tableData: [{name: 'curry', year: 18, sex: 'getting' address: 'tiananmen,},], searchForm: {title: "',}.}; }, methods: { handleSearch() { console.log(this.current); }, handleReset() { this.searchForm = { title: '', }; }, handleAdd() {console.log(' add '); }, handleSelectionChange(val) { console.log(val); }, getTableRef() { console.log(this.$refs.tableTemplate.getTableRef()); ,}}}; </script>