最近在工作中大哥让我修改一下所有页面的table组件 ,要求自己封装一个table组件,减少代码冗余。我们都知道后台便利系统需要大量用到table组件,每次都写基本相同的样式,会使得代码变得臃肿,所以自己对element-ui中的table组件进行二次封装。
最近在写公司后台管理项目时,大哥让我自己封装一个table组件,把页面组件都换了,代码好维护些。我们平时在使用element-ui中的table组件时,如果列多的话html结构将会变得非常臃肿,所以自己封装一个table组件来使用还是非常必要的。
接到任务我就开始着手准备了,我们都知道element的table中的column是我们用到的最多的,所以最先准备的就是配置column列的参数,然后使用v-for进行渲染,这就是基本的骨架了,我们可以看下面为l-table(自己组件的名字)的基本骨架。
<!-- 筛选器 -->
<div class="from-wraper">
<el-form class="toolkit-box" :label-position="align" label-width="90px">
<div class="toolkit-item">
<slot name="toolkit"></slot>
</div>
</el-form>
<el-form class="tookit-buttons">
<slot name="toolkit-buttons"></slot>
</el-form>
</div>
<!-- 表格 -->
<el-table
:data="data"
ref="mutipleTable"
:stripe="options.stripe"
@selection-change="options ? options.mutiSelect.methods : false">
<!--region 选择框-->
<el-table-column
v-if="options && options.mutiSelect.status"
type="selection"
label="全選"
width="55">
</el-table-column>
<!-- 数据展开项 -->
<el-table-column v-if="options.expand" type="expand">
<template slot-scope="scope">
<el-form class="faq-table-expand">
<el-form-item class="faq-detail-title">
<span>Q: {{ scope.row.title }}</span>
</el-form-item>
<el-form-item class="faq-detail-content">
<span>A: {{ scope.row.suggestion }}。</span>
</el-form-item>
</el-form>
</template> -->
</el-table-column>
<!-- 数据列 -->
<template v-for="(column, index) in columns">
<!-- 存在过滤项 -->
<template v-if="column.filters">
<el-table-column :prop="column.prop"
:key='column.label'
:label="column.label"
:align="column.align"
:min-width="column.minWidth"
:sortable="column.sortable"
:filters="column.filters"
:filter-method="filterHandler"
>
<template slot-scope="scope">
<template v-if="!column.render">
<template v-if="column.formatter">
<span v-html="column.formatter(scope.row, column)"></span>
</template>
<template v-else>
<span>{{scope.row[column.prop]}}</span>
</template>
</template>
<template v-else>
<expand-dom :column="column" :row="scope.row" :render="column.render" :index="index" ></expand-dom>
</template>
</template>
</el-table-column>
</template>
<!-- 不存在过滤项 -->
<template v-else>
<el-table-column :prop="column.prop"
:key='column.label'
:label="column.label"
:align="column.align"
:width="column.width"
:sortable="column.sortable"
>
<template slot-scope="scope">
<template v-if="!column.render">
<template v-if="column.formatter">
<span v-html="column.formatter(scope.row, column)"></span>
</template>
<template v-else>
<span>{{scope.row[column.prop]}}</span>
</template>
</template>
<template v-else>
<expand-dom :column="column" :row="scope.row" :render="column.render" :index="index" ></expand-dom>
</template>
</template>
</el-table-column>
</template>
</template>
<!-- 按钮操作组 -->
<el-table-column ref="fixedColumn" label="操作" align="center" :width="operates.width"
v-if="operates.list.filter(_x=>_x.show === true).length > 0">
<template slot-scope="scope">
<div class="operate-group">
<template v-for="(btn, key) in operates.list">
<div class="item" v-if="btn.show" :key='btn.id'>
<el-button :type="btn.type" size="mini" :icon="btn.icon" :disabled="btn.disabled"
:plain="btn.plain" @click.native.prevent="btn.method(key,scope.row)">{{ btn.label }}
</el-button>
</div>
</template>
</div>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="paginartion_wraper">
<el-pagination
:page-size="pagination.size"
@current-change="pagination.handleCurrentChang"
:current-page.sync="pagination.page"
layout="total, prev, pager, next"
:total="pagination.total">
</el-pagination>
</div>
我这里封装的比较全面,基本封装完成后所有页面的table都可以用到,我们着重说el-table的封装,我们都知道table除了column之外还没包含操作列,所以我们的参数主要用到了column(数据列)、operates(操作列)以及options(表格的基本配置)。
pagination: {
size: 50,
position: 'flex-end',
total: 0,
page: 1,
handleCurrentChang: (val) => {
this.handleCurrentChange(val)
}
},
// table基本配置
options: {
stripe: true,
loading: true,
highlightCurrentRow: true,
mutiSelect: false,
expand: true
},
// table列配置
columns: [
COLUMNS.LABEL,
COLUMNS.ID,
COLUMNS.TITLE,
COLUMNS.STATUS
],
// table操作列配置
operates: {
width: 150,
list: [
{
label: '編輯',
type: 'text',
show: true,
disabled: false,
method: (index, row) => {
this.editFaq(row.id)
}
},
{
label: '禁用/發布',
type: 'text',
show: true,
disabled: false,
method: (index, row) => {
this.publishFaq(row, index)
}
},
{
label: '刪除',
type: 'text',
show: true,
disabled: false,
method: (index, row) => {
MessageBox.confirm('確認刪除嗎?此操作不可恢復!', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.removeFaq(row.id)
})
}
}
]
},
这里比较主要的还是column里的数据怎么定义的。
有了骨架之后有了肌肉和血液才完美,所以上面提到的三个主要配置参数就用到了。options和operates都比较好理解,主要是column里的render函数比较难理解,我也是看了很久没弄明白,vue的render函数作用不太懂的同学自行去看文档吧。因为我也不懂,嘿嘿。利用好了这个render函数我们就可以在数据列中任意使用标签啦组件啦这些东西。
请看下面代码我是如何实现使用render函数实现多样化配置的:
export const COLUMNS = {
LABEL: {
prop: 'label', //对应的列
label: '問題類型', //对应列的label
align: 'center', //对齐方式
width: 160, //宽度//灵魂就在于这里,使用render函数我们可以生成虚拟dom,可以生成标签组件等。
render: (h, params) => {
return h('el-tag', {
props: { effect: 'plain' }
}, params.row.label)
}
},
ID: {
prop: 'id',
label: '問題ID',
align: 'center',
width: 170,
render: tableRender.renderFilterId //这是里自己封装的一个列数据组件
},
TITLE: {
prop: 'title',
label: '問題標題',
align: 'center'
},
STATUS: {
prop: 'status',
label: '發布狀態',
align: 'center',
width: 100,
render: (h, params) => {
return h('el-tag', {
props: {
type: params.row.status === 'on' ? 'success' : 'info'
}
}, params.row.status === 'on' ? '已發布' : '未發布')
}
}
}
到了这里就差不多了,我们去试试新的组件好不好使
数据项里面所有有特殊格式的都是靠render函数来实现的。
本次table组件的封装可以实现数据多样化展示,所有table组件配置,数据多样化展示配置,操作按钮的配置均在上面提到的三个参数里面实现。总体来说通过这次的组件封装还是学到了很多东西的。