前言
本次封裝基於 antd
風格, 實現高度可配置的表格封裝配置。本來想通過 vue.extends
去封裝的,奈何幾個月沒寫過 vue
,而且對 vue
的 extends
不熟悉所以放棄了...
之前有小夥伴確實引用了我的程式碼,發現封裝出現了一些紕漏,對此十分抱歉,之前封裝的太倉促了。幾個月前的程式碼,現在重新封裝又有了新的體會。
更新時間 【2018.11.09】,效果如下:
API 說明
columns
: 必選, 列描述資料物件, ArraydataSource
: 必選, 資料陣列options
: 必選, 表格引數控制, maxHeight、stripe 等等..fetch
: 獲取資料的 Functionpagination
: 分頁資訊,不傳則不顯示分頁row-click
:當某一行被點選時會觸發該事件selection-change
: 當選擇項發生變化時會觸發該事件- 其他的 api 可以自行新增
其他說明我在程式碼註釋中寫的很清楚了,請自行檢視。
根據條件渲染: 只通過 render
去判斷引數不同而渲染不一樣的表格資料。 render
函式可以渲染任何你想要的元件
值得注意的是,this
物件的繫結不要出錯了,如果需要更多增強的功能,各位可以自行新增...
Home.vue 元件
<template>
<div>
<h2>Home</h2>
<CommonTable
:columns="columns"
:dataSource="tableData"
:options="options"
:fetch="fetchTableData"
:pagination="pagination"
@row-click="handleRowClick"
@selection-change="handleSelectionChange"
/>
</div>
</template>
<script>
import axios from 'axios'
import CommonTable from '../components/Table'
export default{
components:{
CommonTable
},
data(){
return {
columns: [
{
prop: 'id',
label: '編號',
width: 60
},
{
prop: 'title',
label: '標題',
// render 可以根據你想要渲染的方式渲染
// jsx 不提供 v-model 指令,若你想要使用,,推薦使用外掛 babel-plugin-jsx-v-model
// jsx https://github.com/vuejs/babel-plugin-transform-vue-jsx
render: (row, index) => {
return (
<span style="color: blue" onClick={e => this.handleClick(e, row)}>{row.title}</span>
)
}
},
{
prop: 'author',
label: '作者'
},
{
button: true,
label: '按鈕組',
group: [{
// you can props => type size icon disabled plain
name: '編輯',
type: 'warning',
icon: 'el-icon-edit',
plain: true,
onClick: (row, index) => { // 箭頭函式寫法的 this 代表 Vue 例項
console.log(row, index)
}
}, {
name: '刪除',
type: 'danger',
icon: 'el-icon-delete',
disabled: false,
onClick(row) { // 這種寫法的 this 代表 group 裡的物件
this.disabled = true
console.log(this)
}
}]
}
],
tableData: [
{
id: 1,
title: '標題1',
author: '郭大大'
},
{
id: 2,
title: '標題2',
author: '郭大大2'
}
],
pagination: {
total: 0,
pageIndex: 1,
pageSize: 15
},
options: {
mutiSelect: true,
index: true, // 顯示序號, 多選則 mutiSelect
loading: false, // 表格動畫
initTable: true, // 是否一掛載就載入資料
}
}
},
methods: {
handleClick(e, row){
//transform-vue-jsx 的nativeOnClick 失效 , 所以採用 event.cancelBubble 控制點選事件的冒泡... 如果點選事件不影響你的點選行事件,可以不傳
e.cancelBubble = true // 停止冒泡,否則會觸發 row-click
console.log(row)
},
fetchTableData() {
this.options.loading = true
axios.post('https://www.easy-mock.com/mock/5b3f80edfa972016b39fefbf/example/tableData', {
pageIndex: this.pagination.pageIndex,
pageSize: this.pagination.pageSize
}).then(res => {
const { list, total } = res.data.data
this.tableData = list
this.pagination.total = total
this.options.loading = false
}).catch((error) => {
console.log(error)
this.options.loading = false
})
},
handleRowClick(row, event, column){ // 點選行的事件,同理可以繫結其他事件
console.log('click row:',row, event, column)
},
handleSelectionChange(selection){
console.log(selection)
}
}
}
</script>
複製程式碼
Table.vue 元件
<template>
<div>
<el-table
v-loading="options.loading"
:data="dataSource"
:max-height="options.maxHeight"
:stripe="options.stripe"
:border="options.border"
@row-click="handleRowClick"
@selection-change="handleSelectionChange"
header-row-class-name="table-header-row">
<!--selection選擇框-->
<el-table-column v-if="options.mutiSelect" type="selection" style="width:50px" align="center"></el-table-column>
<!--序號-->
<el-table-column v-if="options.index" label="序號" type="index" width="50" align="center"></el-table-column>
<!--資料列-->
<template v-for="(column, index) in columns">
<el-table-column
:key="index"
:prop="column.prop"
:label="column.label"
:align="column.align||'center'"
:width="column.width"
:fixed="column.fixed">
<template slot-scope="scope">
<template v-if="!column.render">
{{scope.row[column.prop]}}
</template>
<!-- render -->
<template v-else>
<RenderDom :row="scope.row" :index="index" :render="column.render" />
</template>
<!-- render button -->
<template v-if="column.button">
<template v-for="(btn, i) in column.group">
<el-button
:key="i"
:type="btn.type" :size="btn.size || 'mini'" :icon="btn.icon" :disabled="btn.disabled" :plain="btn.plain"
@click.stop="btn.onClick(scope.row, scope.$index)"
>{{btn.name}}</el-button>
</template>
</template>
<!-- slot 你可以其他常用項 -->
</template>
</el-table-column>
</template>
</el-table>
<!-- 分頁 -->
<el-pagination
v-if="pagination"
:total="pagination.total"
:page-sizes="[20, 50, 100, 500, 5000]"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleIndexChange"
style="margin-top: 20px;text-align: right"
></el-pagination>
</div>
</template>
<script>
export default {
components: {
RenderDom: {
functional: true, // 函式式元件 - 無 data 和 this 上下文 => better render
props: {
row: Object,
index: Number,
render: Function
},
/**
* @param {Function} createElement - 原生建立dom元素的方法, 棄用,推薦使用 jsx
* @param {Object} ctx - 渲染的節點的this物件
* @argument 傳遞引數 row index
*/
render(createElement, ctx){
const { row, index } = ctx.props
return ctx.props.render(row, index)
}
}
},
props:{
dataSource: Array,
options: Object, // 表格引數控制 maxHeight、stripe 等等...
columns: Array,
fetch: Function, // 獲取資料的函式
pagination: Object // 分頁,不傳則不顯示
},
created() {
// 傳入的options覆蓋預設設定
this.$parent.options = Object.assign({
maxHeight: 500,
stripe: true, // 是否為斑馬紋
border: true
}, this.options)
this.options.initTable && this.fetch()
},
methods: {
handleSizeChange(size) { // 切換每頁顯示的數量
this.pagination.pageSize = size
this.fetch()
},
handleIndexChange(current) { // 切換頁碼
this.pagination.pageIndex = current
this.fetch()
},
handleSelectionChange(selection) {
this.$emit('selection-change', selection)
},
handleRowClick(row, event, column) {
this.$emit('row-click', row, event, column)
}
}
}
</script>
<style>
.el-table th,
.el-table tr.table-header-row {
background: #e5c5d2; /* 示例, 對錶格樣式上的修飾 */
}
</style>
複製程式碼
結語
上述程式碼封裝完整性可能不是這麼高,但思路在呢,如果需要更多配置,各位可以在進行加強...
吐槽一下,本來是想 props
資料來重寫 table
引數,類似 react
:
<Home>
<ComonTable {...props} >
</Home>
// ComonTable
<el-table {...props.options}>
</el-table>
複製程式碼
所以想到繼承,自己又不熟悉。 而且發現 vue
展開繫結多個屬性是不可以的: 可能是我沒 google
到。如果可以,請大佬告知一聲,謝謝