2020-7-30 seo達人
表格需求
一般管理系統對表格會有以下需求
可以分頁(需要有分頁條)
可以多選(表格帶復選框)
頂部需要加一些操作按鈕(新增,刪除等等)
表格每行行尾有操作按鈕
表格行可以編輯
如下圖為一個示例表格
如果我們直接使用element-ui提供的組件的話,那么開發一個這樣的表格就需要使用到以下內容
需要使用表格的插槽功能,開發每一行的按鈕
需要通過樣式調整頂部按鈕,表格,分頁條的布局樣式
需要監聽分頁的事件然后去刷新表格數據
頂部按鈕或操作按鈕如果需要獲取表格數據,需要調用表格提供的api
對于有行編輯的需求,還需要通過插槽去渲染行編輯的內容,同時要控制行編輯的開關
不僅僅開發表格比較麻煩,而且還要考慮團隊協作,如果每個人實現表格的方式存在差別,那么可能后期的維護成本也會變得很高。那怎么辦呢?
項目安裝
安裝插件
在使用element-ui的項目中,可以通過以下命令進行安裝
npm install vue-elementui-table -S
在項目中使用
在main.js中添加以下代碼
import ZjTable from 'vue-element-table'
Vue.use(ZjTable)
然后即可像下文中的使用方式進行使用
表格配置
為了滿足團隊快速開發的需要,小編對上面提出來的需求進行了封裝,然后使用的時候,開發人員只需要配置一些JSON便可以完成以上功能的開發。
基礎配置
一個基礎的表格包含了數據和列信息,那么如何用封裝的表格去配置呢?
<template>
<zj-table
:columns="columns"
:data="data"
:pagination="false"
/>
</template>
<script>
export default {
data() {
return {
// 表格的列信息, 數組每一項代表一個字段,可以使用element 列屬性的所有屬性,以下僅為示例
columns: Object.freeze([
{
// 表頭顯示的文字
label: '姓名',
// 對應數據里面的字段
prop: 'name'
},
{
label: '性別',
prop: 'sex',
// 格式化表格,與element-ui 的表格屬性相同
formatter(row, column, cellValue) {
return cellValue === 1 ? '男' : '女'
}
},
{
label: '年齡',
prop: 'age'
}
]),
data: [
{
name: '子君',
sex: 1,
age: 18
}
]
}
}
}
</script>
通過上面的配置,就可以完成一個基礎表格的開發,完整代碼見 https://github.com/snowzijun/vue-element-table/blob/master/example/views/demo/base.vue,效果如下圖所示
表格默認會顯示復選框,也可以通過配置selectable屬性來關閉掉
添加分頁
簡單的表格用封裝之后的或未封裝的開發工作量區別并不大,我們繼續為表格添加上分頁
<template>
<!--
current-page.sync 表示頁碼, 添加上 .sync 在頁碼發生變化時自動同步頁碼
page-size.sync 每頁條數
total 總條數
height="auto" 配置height:auto, 表格高度會根據內容自動調整,如果不指定,表格將保持充滿父容器,同時表頭會固定,不跟隨滾動條滾動
@page-change 無論pageSize currentPage 哪一個變化,都會觸發這個事件
-->
<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: [],
// 當前頁碼
currentPage: 1,
// 每頁條數
pageSize: 10,
// 總條數
total: 0,
// 是否顯示loading
loading: false
}
},
created() {
this.loadData()
},
methods: {
// 加載表格數據
loadData() {
this.loading = true
setTimeout(() => {
// 假設總條數是40條
this.total = 40
const { currentPage, pageSize } = this
// 模擬數據請求獲取數據
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() {
// 因為上面設置屬性指定了.sync,所以這兩個屬性會自動變化
console.log(this.pageSize, this.currentPage)
// 分頁發生變化,重新請求數據
this.loadData()
}
}
}
</script>
完整代碼請參考 https://github.com/snowzijun/vue-element-table/blob/master/example/views/demo/pagination.vue
通過封裝,表格將自帶分頁功能,通過上面代碼,實現效果如下所示,是不是變得簡單了一些。接下來我們繼續給表格添加按鈕
添加頂部按鈕
表格上面可能會有新增,刪除等等按鈕,怎么辦呢,接下來我們繼續通過配置去添加按鈕
<template>
<zj-table
:buttons="buttons"
/>
</template>
<script>
export default {
data() {
return {
buttons: Object.freeze([
{
// id 必須有而且是在當前按鈕數組里面是唯一的
id: 'add',
text: '新增',
type: 'primary',
icon: 'el-icon-circle-plus',
click: this.$_handleAdd
},
{
id: 'delete',
text: '刪除',
// rows 是表格選中的行,如果沒有選中行,則禁用刪除按鈕, disabled可以是一個boolean值或者函數
disabled: rows => !rows.length,
click: this.$_handleRemove
},
{
id: 'auth',
text: '這個按鈕根據權限顯示',
// 可以通過返回 true/false來控制按鈕是否顯示
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('點擊了新增按鈕')
},
// 頂部按鈕會自動將表格所選的行傳出來
$_handleRemove(rows) {
const ids = rows.map(({ id }) => id)
this.$alert(`要刪除的行id為${ids.join(',')}`)
},
// 關注作者公眾號
$_handleFollowAuthor() {}
}
}
</script>
表格頂部可以添加普通的按鈕,也可以添加下拉按鈕,同時還可以通過before來配置按鈕是否顯示,disabled來配置按鈕是否禁用,上面完整代碼見 https://github.com/snowzijun/vue-element-table/blob/master/example/views/demo/button.vue
通過上面的代碼就可以配置出下面的表格,是不是很簡單呢?
表格頂部可以有按鈕,行尾也是可以添加按鈕的,一起來看看
行操作按鈕
一般我們會將一些單行操作的按鈕放在行尾,比如編輯,下載等按鈕,那如何給行尾配置按鈕呢?
<template>
<zj-table
:columns="columns"
/>
</template>
<script>
export default {
data() {
return {
columns: Object.freeze([
{
// 可以指定列的寬度,與element-ui原生用法一致
width: 220,
label: '姓名',
prop: 'name'
},
// 行編輯按鈕,在表格末尾出現,自動鎖定右側
{
width: 180,
label: '操作',
// 通過 actions 指定行尾按鈕
actions: [
{
id: 'follow',
text: '關注作者',
click: this.$_handleFollowAuthor
},
{
id: 'edit',
text: '編輯',
// 可以通過before控制按鈕是否顯示,比如下面年齡四十歲的才會顯示編輯按鈕
before(row) {
return row.age < 40
},
click: this.$_handleEdit
},
{
id: 'delete',
text: '刪除',
icon: 'el-icon-delete',
disabled(row) {
return row.sex === 0
},
// 為了拿到this,這里需要用箭頭函數
click: () => {
this.$alert('女生被禁止刪除了')
}
}
]
}
])
}
},
methods: {
// 關注作者公眾號
$_handleFollowAuthor() {
console.log('微信搜索【前端有的玩】,這是對小編最大的支持')
},
/**
* row 這一行的數據
*/
$_handleEdit(row, column) {
this.$alert(`點擊了姓名為【${row.name}】的行上的按鈕`)
}
}
}
</script>
行操作按鈕會被凍結到表格最右側,不會跟隨滾動條滾動而滾動,上面完整代碼見, https://github.com/snowzijun/vue-element-table/blob/master/example/views/demo/button.vue
通過上面的代碼就可以完成以下效果
最后再來一起看看行編輯
行編輯
比如上例,我希望點擊行尾的編輯按鈕的時候,可以直接在行上面編輯用戶的姓名與性別,如何配置呢?
<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: '請輸入姓名'
}
]
}
},
{
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: '編輯',
// 如果當前行啟用了編輯,則不顯示編輯按鈕
before: row => {
return !this.editIds.includes(row.id)
},
click: this.$_handleEdit
},
{
id: 'save',
text: '保存',
// 如果當前行啟用了編輯,則顯示保存按鈕
before: row => {
return this.editIds.includes(row.id)
},
click: this.$_handleSave
}
]
}
]),
data: [
{
// 行編輯必須指定rowKey字段,默認是id,如果修改為其他字段,需要給表格指定row-key="字段名"
id: '0',
name: '子君',
sex: '1',
age: 18
},
{
// 行編輯必須指定rowKey字段,默認是id,如果修改為其他字段,需要給表格指定row-key="字段名"
id: '1',
name: '子君1',
sex: '0',
age: 18
}
],
editIds: []
}
},
methods: {
$_handleEdit(row) {
// 通過調用 startEditRow 可以開啟行編輯
this.$refs.table.startEditRow(row.id)
// 記錄開啟了行編輯的id
this.editIds.push(row.id)
},
$_handleSave(row) {
// 點擊保存的時候,通過endEditRow 結束行編輯
this.$refs.table.endEditRow(row.id, (valid, result, oldRow) => {
// 如果有表單驗證,則valid會返回是否驗證成功
if (valid) {
console.log('修改之后的數據', result)
console.log('原始數據', oldRow)
const index = this.editIds.findIndex(item => item === row.id)
this.editIds.splice(index, 1)
} else {
// 如果校驗失敗,則返回校驗的第一個輸入框的異常信息
console.log(result)
this.$message.error(result.message)
}
})
}
}
}
</script>
不需要使用插槽就可以完成行編輯,是不是很開心。上述完整代碼見 https://github.com/snowzijun/vue-element-table/blob/master/example/views/demo/row-edit.vue
效果如下圖所示:
其他功能
除了上面的功能之外,表格還可以配置其他許多功能,比如
可以指定字段為鏈接列,需要給列配置link屬性
可以通過插槽自定義頂部按鈕,行操作按鈕,行字段等
可以在按鈕區域右側通過插槽配置其他內容
其他等等
表格開發說明
通過上面的代碼示例,我們已經知道了封裝之后的表格可以完成哪些事情,接下來一起來看看表格是如何實現的。完整代碼見 https://github.com/snowzijun/vue-element-table/tree/master/src/components/zj-table
表格布局
整個表格是通過JSX來封裝的,因為JSX使用起來更加靈活。對于我們封裝的表格,我們從豎向可以分為三部分,分別是頂部按鈕區,中間表格區,底部分頁區,如何去實現三個區域的布局呢,核心代碼如下
render(h) {
// 按鈕區域
const toolbar = this.$_renderToolbar(h)
// 表格區域
const table = this.$_renderTable(h)
// 分頁區域
const page = this.$_renderPage(h)
return (
<div class="zj-table" style={{ height: this.tableContainerHeight }}>
{toolbar}
{table}
{page}
</div>
)
}
通過三個render函數分別渲染對應區域,然后將三個區域組合在一起。
渲染表格列
通過前文的講解,我們可以將表格的列分為以下幾種
常規列
行編輯列
操作按鈕列
插槽列
鏈接列(文檔后續完善)
嵌套列(文檔后續完善)
$_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為非空數組
actions = [],
// 是否可編輯列, 對于可編輯列需要動態啟用編輯
editable = false,
// 是否有嵌套列
nests,
// 是否可點擊
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 {
// 使用默認列
return this.$_renderDefaultColumn(h, column)
}
})
},
行編輯列
當前表格行編輯支持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') {
// 如果自定義,可以通過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
}
// 事件改寫
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
}}
/>
)
}
藍藍設計( paul-jarrel.com )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務