作為一枚做後臺管理系統的前端,除了羨慕做移動端或小程式的同行,就是經常被要求做一個XX的維護頁面! 這不,這周PO又說:小X啊,給系統做個手機號歸屬地的維護頁面吧!
什麼是維護頁面?就是無聊透頂的增刪改查頁面唄! 反正有現成的UI框架,然後就是對著文件寫一些自定義標籤、配置下屬性、通過後端給的介面獲取資料填充上...
因此,基本的維護頁面元件大致是這個樣子:
<template>
<div>
<el-table :data="tableData">
<el-table-column prop="key1" label="value2"></el-table-column>
<el-table-column prop="key2" label="value2"></el-table-column>
...
<el-table-column label="操作">
<template slot-scope="scope">
<el-button @click="handleEdit">編輯</el-button>
<el-button @click="handleDel">刪除</el-button>
</template>
</el-table-column>
</div>
</template>
複製程式碼
最終呈現的頁面:
但是,這次終於爆發了,不想再做這種重複性工作了!(當然不是拒絕不做) 想著,要是通過配置JSON,直接生成頁面就好了! 尋思著,對Element-UI的Tabel元件再做一層封裝! 最終,只要配置以下JSON引數,就可以自動生成需要的頁面:
const options = {
table: {
columns: [
{
prop: 'value1',
label: 'key1'
},
{
prop: 'value2',
label: 'key2'
}
],
handle: getData
}
};
複製程式碼
這是最基本的配置,但Element-UI的Table元件本身還支援很多配置引數,這些配置若也在JSON中,也要正常作用。因此,template模板寫法並不適用,或者說自由度不高,所以採用了JSX的寫法:
export default {
props: {
options: Object
},
data() {
return {
tableData: []
};
};
render(h) {
const tpl = <div></div>;
const tableTpl = <el-table data={ this.tableData }></el-table>;
const options = this.options;
const componentOptions = tableTpl.componentOptions;
// 遍歷傳入的屬性,配置在原生的Element Table元件上
(let option in options.table) {
componentOptions.propsData[option] = options.table[option];
}
options.table.columns.forEach(column => {
const columnTpl = <column options={ column }></column>;
componentOptions.children.push(columnTpl);
});
tpl.children.push(tableTpl);
return tpl;
},
methods: {
getData() {
const options = this.options;
const params = {};
options.handle && options.handle(params).then(res => {
if (res.status === 0) {
this.tableData = res.result.Body;
}
});
}
},
created() {
this.getData();
}
}
複製程式碼
根元素用div,而不直接用el-table,是方便為了以後加入分頁與表單篩選。
其實,表格的最後一列,雖然作為維護頁面基本就是編輯與刪除,但也不保證沒有變動!需求這種東西誰知道呢。因此,將最後一列的內容與邏輯都丟擲來,不放在元件裡實現,但要保證其擁有原先的作用域。這裡,就需要藉助vue的作用域插槽,比如我們是這麼使用元件的:
<custom-table :options="options">
<template slot-scope="scope">
<el-button size="small" type="text" @click="handleClick(scope)">編輯</el-button>
</template>
</custom-table>
複製程式碼
這裡的點選事件處理方法的引數scope,就是原生el-table-column元件的作用域,即 scope = { row, column, $index }。 因此,需要對el-table-column也做一層封裝:
components: {
Column: {
props: {
options: Object
},
render(h) {
const tpl = <el-table-column ></el-table-column>;
const options = this.options;
const componentOptions = tpl.componentOptions;
for (let option in options) {
if (option === 'slot') {
const slot = this.$parent.$parent.$scopedSlots.default;
tpl.data['scopedSlots'] = {
default: scope => {
return [slot(scope)];
}
};
}
else {
componentOptions.propsData[option] = options[option];
}
}
return tpl;
}
}
複製程式碼
這裡要注意,獲取的slot是一個函式,需要執行再傳入。
到這裡,其實只是滿足了最最基本的資料展示,還有許多功能並未實現,比如資料行的選擇之類的。之後的實現會加入分頁與表單!
若有寫的不好的地方,歡迎指出!