寫在前面
感謝 餓了麼前端團隊提供元件化框架elememt-ui,本文基礎元件使用element-ui。
大背景
在開發一些系統過程中,使用table作資料展示在所難免。先來看看el-table元件。
非常簡單易用的元件,根據提供的data資料,配置table每一列的資料和label。沒錯,這樣似乎都是ok的,但是在開發大量包含table的頁面,會發現每次都需要去複製el-table-column,或者你會說你已經很屬性element-ui整套框架的文件。然而,重複的程式碼很多及程式碼量很大。作為一名程式設計師,某一天需要寫自己已經寫過的某段程式碼,是不是感覺有點不應該呢。。。
資料驅動
<
el-table :data="tabledata">
<
el-table-column v-for="(item,key) in columnsConfig" :key="key" :label="item.label" :prop="item.prop">
<
/el-table-column>
<
/el-table>
複製程式碼
data () {
return {
columnsConfig: [{
prop: 'logicCategoryId', label: '編號(ID)'
}, {
prop: 'name', label: '分類名稱'
}]
}
}複製程式碼
這樣可以很輕鬆的渲染出來table。
這裡有個小技巧
el-table-column改造下
<
el-table :data="tabledata">
<
el-table-column v-for="(item,key) in columnsConfig" :key="key" v-bind="item">
// 這裡改造 <
/el-table-column>
<
/el-table>
複製程式碼
v-bind可以繫結一個物件,這樣會讀取item物件的每個屬性,使用到元件當中去。比如增加width: 100,只需要在columnsConfig沒一項增加width即可,el-table-column不需要改動。
使用slots怎麼辦
<
el-table-column label="日期" width="120">
<
template scope="scope">
{{
scope.row.date
}
}<
/template>
<
/el-table-column>
複製程式碼
很明顯,el-table-column的slots配置在columnsConfig陣列不能用。在原始碼找到解決辦法(檔案路徑:node_modules_element-ui@1.3.7@element-ui\packages\table\src\table-column.js),create鉤子函式程式碼如下:
在this.columnConfig.renderCell函式渲染每一個table cell,如果使用slots會讀取,slots中的內容。編寫一個新元件使用vue extends,繼承el-table-columns,重寫了renderCell函式改變其返回內容,這時候用jsx將內容用return slots的函式傳回來。
首先,看看columnsConfig怎麼寫
columnsConfig: [{
cellType: 'slots',// 不是所有的列都需要重寫,加個欄位標記下 prop: 'logicCategoryId', label: '編號(ID)', renderCell: (scope) =>
{
return ( <
el-button type="text" on-click={() =>
that.viewGoods(scope.row)
}>
{
scope.row.productCount
} <
/el-button>
)
}
}, {
prop: 'name', label: '分類名稱'
}],複製程式碼
其次,開發新元件 column-plus.vue,程式碼如下
<
script>
import {
TableColumn
} from 'element-ui'// renderCell 函式,型別可擴充套件const renderCell = {
slots: function (h, data) {
// 接受傳入的renderCell函式 let renderCell = () =>
{
return this.renderCell ? this.renderCell(data) : ''
} return <
div class="cell">
{
renderCell(h, data)
}<
/div>
}
}export default {
extends: TableColumn,// 繼承el-table-column props: {
prop: {
type: [String, Number]
}, cellType: {
type: String, validator: function (value) {
let valid = ['text', 'input', 'slots'].includes(value) !valid &
&
console.error(`columnPlus元件不適配 ${value
} 型別`) return valid
}
}, renderCell: {
type: Function
}
}, // el-table-column 先呼叫在呼叫本身的 created () {
if (renderCell[this.cellType]) {
this.columnConfig.renderCell = renderCell[this.cellType].bind(this)
}
}
}<
/script>
複製程式碼
最後,元件用通過模板,配置資料即可
<
el-table :data="tabledata">
<
column-plus v-bind="item" v-for="(item,key) in columnConfigs" :key="key">
<
/column-plus>
<
/el-table>
複製程式碼
配置資料
columnsConfig: [{
cellType: 'slots', prop: 'logicCategoryId', label: '編號(ID)', renderCell: (scope) =>
{
return ( <
el-button type="text" on-click={() =>
that.viewGoods(scope.row)
}>
{
scope.row.productCount
} <
/el-button>
)
}
}, {
prop: 'name', label: '分類名稱'
}]****複製程式碼
寫在後面
元件開發實現可配置開發,可達到快速開發的目的和簡化程式碼。需要說明vue extends和mixins屬性,這兩個屬性都是繼承,屬性和方法重寫,鉤子函式是先呼叫父類在呼叫自己的,上面的例子(el-table-column 先呼叫在呼叫本身的),但是區別是:
- extends單繼承,同時使用優先順序高
- mixins多繼承,同時使用優先順序低
另外,vue-cli使用jsx編寫需要安裝三個外掛。
- babel-helper-vue-jsx-merge-props
- babel-plugin-syntax-jsx
- babel-plugin-transform-vue-jsx
補充
釋出了一天沒想到有這麼小夥伴閱讀,有幾點需要補充下。
評論區 @hold 評論更iview如出一轍,後來去翻看iview的文件確實,一直都沒用iview開發過,不知道table也是用render來實現的,確實分享之後自己學到了更多,感謝@hold。
這是iview,table元件的程式碼
render: (h, params) =>
{
return h('div', [ h('Button', {
props: {
type: 'text', size: 'small'
}
}, 'View'), h('Button', {
props: {
type: 'text', size: 'small'
}
}, 'Edit') ]);
}複製程式碼
當然使用render之後,需要使用filter,就比較尷尬了。不過,vue的filter其實也是語法糖,最終編譯是編譯成函式處理。
那如果想使用filter怎麼辦?
data () {
return {
columns: [{
renderCell: (scope) =>
{
return ( {
that.stateTxt(scope.row.state)
} )
}
}]
}
}, methods: {
stateTxt (val) {
}
}複製程式碼
寫過react都知道是這麼幹的。
所以,一直以來前端把js寫在html中,還是把html寫js中,都是爭論不休的話題,如何選擇還開發自己拿捏。
不使用render程式碼是這樣的
<
template>
<
el-table :data="tableData" style="width: 100%">
<
el-table-column prop="date" label="日期" width="180">
<
/el-table-column>
<
el-table-column prop="name" label="姓名" width="180">
<
/el-table-column>
<
el-table-column prop="address" label="地址">
<
/el-table-column>
<
/el-table>
<
/template>
複製程式碼
使用render處理是這樣的
<
el-table :data="tabledata">
<
column-plus v-bind="item" v-for="(item,key) in columnConfigs" :key="key">
<
/column-plus>
<
/el-table>
data () {
return {
columnConfigs: [{
label: '日期', width: '180', prop: 'date'
}, {
label: '姓名', width: '180', prop: 'name'
}, {
label: '地址', prop: 'address'
}]
}
}複製程式碼