項(xiàng)目安裝安裝插件
在使用element-ui的項(xiàng)目中虱歪,可以通過(guò)以下命令進(jìn)行安裝
npm install vue-elementui-table -S復(fù)制代碼在項(xiàng)目中使用
在main.js中添加以下代碼
import ZjTable from 'vue-elementui-table'Vue.use(ZjTable)
然后即可像下文中的使用方式進(jìn)行使用
表格配置
為了滿足團(tuán)隊(duì)快速開(kāi)發(fā)的需要棒动,小編對(duì)上面提出來(lái)的需求進(jìn)行了封裝,然后使用的時(shí)候语御,開(kāi)發(fā)人員只需要配置一些JSON便可以完成以上功能的開(kāi)發(fā)。
基礎(chǔ)配置
一個(gè)基礎(chǔ)的表格包含了數(shù)據(jù)和列信息,那么如何用封裝的表格去配置呢麦箍?
<template> <zj-table :columns="columns" :data="data" :pagination="false" /></template><script>export default { data() { return { // 表格的列信息, 數(shù)組每一項(xiàng)代表一個(gè)字段,可以使用element 列屬性的所有屬性陶珠,以下僅為示例 columns: Object.freeze([ { // 表頭顯示的文字 label: '姓名', // 對(duì)應(yīng)數(shù)據(jù)里面的字段 prop: 'name' }, { label: '性別', prop: 'sex', // 格式化表格,與element-ui 的表格屬性相同 formatter(row, column, cellValue) { return cellValue === 1 ? '男' : '女' } }, { label: '年齡', prop: 'age' } ]), data: [ { name: '子君', sex: 1, age: 18 } ] } }}</script>通過(guò)上面的配置挟裂,就可以完成一個(gè)基礎(chǔ)表格的開(kāi)發(fā),完整代碼見(jiàn) github.com/snowzijun/v…揍诽,效果如下圖所示
表格默認(rèn)會(huì)顯示復(fù)選框诀蓉,也可以通過(guò)配置selectable屬性來(lái)關(guān)閉掉
添加分頁(yè)
簡(jiǎn)單的表格用封裝之后的或未封裝的開(kāi)發(fā)工作量區(qū)別并不大,我們繼續(xù)為表格添加上分頁(yè)
<template><!-- current-page.sync 表示頁(yè)碼, 添加上 .sync 在頁(yè)碼發(fā)生變化時(shí)自動(dòng)同步頁(yè)碼 page-size.sync 每頁(yè)條數(shù) total 總條數(shù) height="auto" 配置height:auto, 表格高度會(huì)根據(jù)內(nèi)容自動(dòng)調(diào)整暑脆,如果不指定渠啤,表格將保持充滿父容器,同時(shí)表頭會(huì)固定添吗,不跟隨滾動(dòng)條滾動(dòng) @page-change 無(wú)論pageSize currentPage 哪一個(gè)變化沥曹,都會(huì)觸發(fā)這個(gè)事件 --> <zj-table v-loading="loading" :columns="columns" :data="data" :current-page.sync="currentPage" :page-size.sync="pageSize" :total="total" height="auto" @page-change="$_handlePageChange" /></template><script>export default { data() { return { columns: Object.freeze([ // 列字段與上例一樣,此處省略 ]), data: [], // 當(dāng)前頁(yè)碼 currentPage: 1, // 每頁(yè)條數(shù) pageSize: 10, // 總條數(shù) total: 0, // 是否顯示loading loading: false } }, created() { this.loadData() }, methods: { // 加載表格數(shù)據(jù) loadData() { this.loading = true setTimeout(() => { // 假設(shè)總條數(shù)是40條 this.total = 40 const { currentPage, pageSize } = this // 模擬數(shù)據(jù)請(qǐng)求獲取數(shù)據(jù) this.data = new Array(pageSize).fill({}).map((item, index) => { return { name: `子君${currentPage + (index + 1) * 10}`, sex: Math.random() > 0.5 ? 1 : 0, age: Math.floor(Math.random() * 100) } }) this.loading = false }, 1000) }, $_handlePageChange() { // 因?yàn)樯厦嬖O(shè)置屬性指定了.sync,所以這兩個(gè)屬性會(huì)自動(dòng)變化 console.log(this.pageSize, this.currentPage) // 分頁(yè)發(fā)生變化,重新請(qǐng)求數(shù)據(jù) this.loadData() } }}</script>
完整代碼請(qǐng)參考 github.com/snowzijun/v…
通過(guò)封裝妓美,表格將自帶分頁(yè)功能,通過(guò)上面代碼僵腺,實(shí)現(xiàn)效果如下所示,是不是變得簡(jiǎn)單了一些。接下來(lái)我們繼續(xù)給表格添加按鈕
添加頂部按鈕
表格上面可能會(huì)有新增壶栋,刪除等等按鈕辰如,怎么辦呢,接下來(lái)我們繼續(xù)通過(guò)配置去添加按鈕
<template> <zj-table :buttons="buttons" /></template><script>export default { data() { return { buttons: Object.freeze([ { // id 必須有而且是在當(dāng)前按鈕數(shù)組里面是唯一的 id: 'add', text: '新增', type: 'primary', icon: 'el-icon-circle-plus', click: this.$_handleAdd }, { id: 'delete', text: '刪除', // rows 是表格選中的行委刘,如果沒(méi)有選中行丧没,則禁用刪除按鈕, disabled可以是一個(gè)boolean值或者函數(shù) disabled: rows => !rows.length, click: this.$_handleRemove }, { id: 'auth', text: '這個(gè)按鈕根據(jù)權(quán)限顯示', // 可以通過(guò)返回 true/false來(lái)控制按鈕是否顯示 before: (/** rows */) => { return true } }, // 可以配置下拉按鈕哦 { id: 'dropdown', text: '下拉按鈕', children: [ { id: 'moveUp', text: '上移', icon: 'el-icon-arrow-up', click: () => { console.log('上移') } }, { id: 'moveDown', text: '下移', icon: 'el-icon-arrow-down', disabled: rows => !rows.length, click: () => { console.log('下移') } } ] } ]) } }, created() {}, methods: { // 新增 $_handleAdd() { this.$alert('點(diǎn)擊了新增按鈕') }, // 頂部按鈕會(huì)自動(dòng)將表格所選的行傳出來(lái) $_handleRemove(rows) { const ids = rows.map(({ id }) => id) this.$alert(`要?jiǎng)h除的行id為${ids.join(',')}`) },
$_handleFollowAuthor() {} }}</script>
表格頂部可以添加普通的按鈕,也可以添加下拉按鈕锡移,同時(shí)還可以通過(guò)before來(lái)配置按鈕是否顯示呕童,disabled來(lái)配置按鈕是否禁用,上面完整代碼見(jiàn) github.com/snowzijun/v…
通過(guò)上面的代碼就可以配置出下面的表格,是不是很簡(jiǎn)單呢淆珊?
表格頂部可以有按鈕夺饲,行尾也是可以添加按鈕的,一起來(lái)看看
行操作按鈕
一般我們會(huì)將一些單行操作的按鈕放在行尾施符,比如編輯往声,下載等按鈕,那如何給行尾配置按鈕呢?
<template> <zj-table :columns="columns" /></template><script>export default { data() { return { columns: Object.freeze([ { // 可以指定列的寬度戳吝,與element-ui原生用法一致 width: 220, label: '姓名', prop: 'name' }, // 行編輯按鈕浩销,在表格末尾出現(xiàn),自動(dòng)鎖定右側(cè) { width: 180, label: '操作', // 通過(guò) actions 指定行尾按鈕 actions: [ { id: 'follow', text: '關(guān)注作者', click: this.$_handleFollowAuthor }, { id: 'edit', text: '編輯', // 可以通過(guò)before控制按鈕是否顯示听哭,比如下面年齡四十歲的才會(huì)顯示編輯按鈕 before(row) { return row.age < 40 }, click: this.$_handleEdit }, { id: 'delete', text: '刪除', icon: 'el-icon-delete', disabled(row) { return row.sex === 0 }, // 為了拿到this,這里需要用箭頭函數(shù) click: () => { this.$alert('女生被禁止刪除了') } } ] } ]) } }, methods: { $_handleFollowAuthor() { console.log('微信搜索牛課網(wǎng)') }, /** * row 這一行的數(shù)據(jù) */ $_handleEdit(row, column) { this.$alert(`點(diǎn)擊了姓名為【${row.name}】的行上的按鈕`) } }}</script>
行操作按鈕會(huì)被凍結(jié)到表格最右側(cè)慢洋,不會(huì)跟隨滾動(dòng)條滾動(dòng)而滾動(dòng),上面完整代碼見(jiàn), github.com/snowzijun/v…
通過(guò)上面的代碼就可以完成以下效果
最后再來(lái)一起看看行編輯
行編輯
比如上例陆盘,我希望點(diǎn)擊行尾的編輯按鈕的時(shí)候普筹,可以直接在行上面編輯用戶的姓名與性別,如何配置呢?
<template> <zj-table ref="table" :columns="columns" :data="data" /></template><script>export default { data() { return { columns: Object.freeze([ { label: '姓名', prop: 'name', editable: true, field: { componentType: 'input', rules: [ { required: true, message: '請(qǐng)輸入姓名' } ] } }, { label: '性別', prop: 'sex', // 格式化表格,與element-ui 的表格屬性相同 formatter(row, column, cellValue) { return cellValue === '1' ? '男' : '女' }, editable: true, field: { componentType: 'select', options: [ { label: '男', value: '1' }, { label: '女', value: '0' } ] } }, { label: '年齡', prop: 'age', editable: true, field: { componentType: 'number' } }, { label: '操作', actions: [ { id: 'edit', text: '編輯', // 如果當(dāng)前行啟用了編輯隘马,則不顯示編輯按鈕 before: row => { return !this.editIds.includes(row.id) }, click: this.$_handleEdit }, { id: 'save', text: '保存', // 如果當(dāng)前行啟用了編輯太防,則顯示保存按鈕 before: row => { return this.editIds.includes(row.id) }, click: this.$_handleSave } ] } ]), data: [ { // 行編輯必須指定rowKey字段,默認(rèn)是id,如果修改為其他字段酸员,需要給表格指定row-key="字段名" id: '0', name: '子君', sex: '1', age: 18 }, { // 行編輯必須指定rowKey字段蜒车,默認(rèn)是id,如果修改為其他字段,需要給表格指定row-key="字段名" id: '1', name: '子君1', sex: '0', age: 18 } ], editIds: [] } }, methods: { $_handleEdit(row) { // 通過(guò)調(diào)用 startEditRow 可以開(kāi)啟行編輯 this.$refs.table.startEditRow(row.id) // 記錄開(kāi)啟了行編輯的id this.editIds.push(row.id) }, $_handleSave(row) { // 點(diǎn)擊保存的時(shí)候沸呐,通過(guò)endEditRow 結(jié)束行編輯 this.$refs.table.endEditRow(row.id, (valid, result, oldRow) => { // 如果有表單驗(yàn)證醇王,則valid會(huì)返回是否驗(yàn)證成功 if (valid) { console.log('修改之后的數(shù)據(jù)', result) console.log('原始數(shù)據(jù)', oldRow) const index = this.editIds.findIndex(item => item === row.id) this.editIds.splice(index, 1) } else { // 如果校驗(yàn)失敗,則返回校驗(yàn)的第一個(gè)輸入框的異常信息 console.log(result) this.$message.error(result.message) } }) } } }</script>
不需要使用插槽就可以完成行編輯崭添,是不是很開(kāi)心寓娩。上述完整代碼見(jiàn) github.com/snowzijun/v…
效果如下圖所示:
其他功能
除了上面的功能之外,表格還可以配置其他許多功能,比如
可以指定字段為鏈接列棘伴,需要給列配置link屬性
可以通過(guò)插槽自定義頂部按鈕寞埠,行操作按鈕,行字段等
可以在按鈕區(qū)域右側(cè)通過(guò)插槽配置其他內(nèi)容
其他等等
表格開(kāi)發(fā)說(shuō)明
通過(guò)上面的代碼示例焊夸,我們已經(jīng)知道了封裝之后的表格可以完成哪些事情仁连,接下來(lái)一起來(lái)看看表格是如何實(shí)現(xiàn)的。完整代碼見(jiàn) github.com/snowzijun/v…
表格布局
整個(gè)表格是通過(guò)JSX來(lái)封裝的阱穗,因?yàn)镴SX使用起來(lái)更加靈活饭冬。對(duì)于我們封裝的表格,我們從豎向可以分為三部分揪阶,分別是頂部按鈕區(qū)昌抠,中間表格區(qū),底部分頁(yè)區(qū)鲁僚,如何去實(shí)現(xiàn)三個(gè)區(qū)域的布局呢炊苫,核心代碼如下
render(h) { // 按鈕區(qū)域 const toolbar = this.$_renderToolbar(h) // 表格區(qū)域 const table = this.$_renderTable(h) // 分頁(yè)區(qū)域 const page = this.$_renderPage(h) return ( <div class="zj-table" style={{ height: this.tableContainerHeight }}> {toolbar} {table} {page} </div> ) }
通過(guò)三個(gè)render函數(shù)分別渲染對(duì)應(yīng)區(qū)域,然后將三個(gè)區(qū)域組合在一起冰沙。
渲染表格列
通過(guò)前文的講解,我們可以將表格的列分為以下幾種
常規(guī)列
行編輯列
操作按鈕列
插槽列
鏈接列(文檔后續(xù)完善)
嵌套列(文檔后續(xù)完善)
$_renderColumns(h, columns) { // 整體是否排序 let sortable = this.sortable ? 'custom' : false return columns .filter(column => { const { hidden } = column if (hidden !== undefined) { if (typeof hidden === 'function') { return hidden({ columns, column }) } return hidden } return true }) .map(column => { const { useSlot = false, // 如果存在操作按鈕侨艾,則actions為非空數(shù)組 actions = [], // 是否可編輯列, 對(duì)于可編輯列需要?jiǎng)討B(tài)啟用編輯 editable = false, // 是否有嵌套列 nests, // 是否可點(diǎn)擊 link = false } = column let newSortable = sortable if (column.sortable !== undefined) { newSortable = column.sortable ? 'custom' : false } column = { ...column, sortable: newSortable } if (nests && nests.length) { // 使用嵌套列 return this.$_renderNestColumn(h, column) } else if (editable) { // 使用編輯列 return this.$_renderEditColumn(h, column) } else if (useSlot) { // 使用插槽列 return this.$_renderSlotColumn(h, column) } else if (actions && actions.length > 0) { // 使用操作列 column.sortable = false return this.$_renderActionColumn(h, column) } else if (link) { // 使用鏈接列 return this.$_renderLinkColumn(h, column) } else { // 使用默認(rèn)列 return this.$_renderDefaultColumn(h, column) } }) },復(fù)制代碼行編輯列
當(dāng)前表格行編輯支持input,select,datepicker,TimeSelect,InputNumber等組件拓挥,具體渲染代碼如下所示
// 編輯單元格 $_renderEditCell(h, field) { const components = { input: Input, select: ZjSelect, date: DatePicker, time: TimeSelect, number: InputNumber } const componentType = field.componentType const component = components[componentType] if (component) { return this.$_renderField(h, field, component) } else if (componentType === 'custom') { // 如果自定義唠梨,可以通過(guò)component指定組件 return this.$_renderField(h, field, field.component) } return this.$_renderField(h, field, Input) }, $_renderField(h, field, Component) { // 編輯行的id字段 const { rowId, events = {}, nativeEvents = {} } = field const getEvents = events => { const newEvents = {} Object.keys(events).forEach(key => { const event = events[key] newEvents[key] = (...rest) => { const args = [ ...rest, { rowId, row: this.editRowsData[rowId], value: this.editRowsData[rowId][field.prop] } ] return event(...args) } }) return newEvents } // 事件改寫(xiě) const newEvents = getEvents(events) const newNativeEvents = getEvents(nativeEvents) return ( <Component size="small" on={newEvents} nativeOn={newNativeEvents} v-model={this.editRowsData[rowId][field.prop]} {...{ attrs: field, props: field }} /> ) }