赞
踩
在日常开发中,我们经常会遇到需要展示列表数据的场景。ElementUI 提供的 el-table 组件是一个功能强大的表格组件,可以满足大部分的需求。但是,在实际应用中,我们往往需要根据业务需求对 el-table 组件进行二次封装,以提高开发效率和代码的复用性。
本文将介绍 Vue2+ElementUI 列表组件的封装方法,包括:
封装思路
封装 el-table 组件的思路是将其作为一个独立的组件,对外暴露必要的属性和方法,并通过插槽机制来定制表格的内容。
具体来说,我们可以将 el-table 组件的封装分为以下几个步骤:
创建组件,名为:H3yunTableCompV1
,这是子组件
<template> <div> <el-table ref="multipleTable" tooltip-effect="dark" style="width: 100%" > <el-table-column type="index"> </el-table-column> </el-table> </div> </template> <script> export default { name: "H3yunTableCompV1", data() { return {} }, methods: {} } </script> <style scoped> </style>
创建测试类并使用上面的组件,方便测试。注意:导入组件时注意路径。这是父组件。
<template> <div class="container" style="min-height: 100%; padding-bottom: 100px;"> <H3yunTableCompV1></H3yunTableCompV1> </div> </template> <script> import H3yunTableCompV1 from "../../components/table/H3yunTableCompV1"; export default { props: [], components: { H3yunTableCompV1 }, data() { return {} }, watch: {}, computed: {}, beforeCreate() { }, created() { }, beforeMount() { }, mounted() { }, beforeUpdate() { }, updated() { }, destroyed() { }, methods: {}, } </script> <style scoped> .container { } </style>
父组件编写表格对象并传递给子组件。
<H3yunTableCompV1 :data="tableObj"></H3yunTableCompV1> data() { return { // 这个对象可以从后端获取,下面是一些示例数据 tableObj: { // 数据列 - 即el-table-column组件中的属性 columns: [ {prop: 'date', label: '日期', width: '180'}, {prop: 'name', label: '名字', width: '180'}, {prop: 'address', label: '地址', width: '180'} ] } } }
子组件接收值并处理
export default { name: "H3yunTableCompV1", data() { return { // 表格对象 -- 1 tableObj: { columns: [] } } }, // 接收父组件传递过来的值 props: { // 接收父组件传递过来的data数据,类型为Object -- 2 data: Object }, watch: { // 监控父组件中的data,保证子组件中的tableObj与父组件一致 -- 3 data: { deep: true, // 深度监控 immediate: true, // 在组件创建时立即触发 handler(newVal, oldVal) { this.init(newVal) // 初始化 } } }, methods: { // 初始化方法 -- 4 init(newVal) { for (const key in newVal) { // 如果父组件传的值能与tableObj的属性匹配,比如父子组件都有tableObj.columns,则会进入这个if if (Object.keys(this.tableObj).includes(key)) { // 比如:tableObj.columns = newVal.columns this.tableObj[key] = newVal[key] } } } } }
<el-table ref="multipleTable" tooltip-effect="dark" style="width: 100%" > <el-table-column type="index"> </el-table-column> <el-table-column v-for="(column,key) in tableObj.columns" :key="key" :prop="column.prop" :label="column.label" :width="column.width" > </el-table-column> </el-table>
效果如下
比如说我想隐藏ID列。我给id这个配置添加一个属性为hide:true
。
tableObj: {
// 数据列 - 即el-table-column组件中的属性
columns: [
{prop: 'id', label: 'ID', width: '80', hide: true},
{prop: 'date', label: '日期', width: '180'},
{prop: 'name', label: '名字', width: '180'},
{prop: 'address', label: '地址', width: '180'}
]
}
id列未隐藏之前的效果。
子组件的el-table-column
循环时加个属性v-if="!column.hide"
。注意:这里使用v-show
的话是不起作用的。
<el-table-column
v-for="(column,key) in tableObj.columns"
:key="key"
:prop="column.prop"
:label="column.label"
:width="column.width"
v-if="!column.hide"
>
</el-table-column>
隐藏后的效果
先看效果,标题列是通过插槽的方式插入的。
子组件使用v-if
去判断是否是插槽去做分别处理。下面是完整的代码,里面使用了临时数据,后面会通过父组件传递。
<template> <div> <el-table ref="multipleTable" tooltip-effect="dark" style="width: 100%" :data="tableData" @selection-change="handleSelectionChange" > <!--多选--> <el-table-column type="selection" width="55"> </el-table-column> <!--序号--> <el-table-column type="index"> </el-table-column> <!--插槽处理--> <template v-for="(column,key) in tableObj.columns"> <el-table-column :key="key" :prop="column.prop" :label="column.label" :width="column.width" v-if="column.type == 'slot'" > <template slot-scope="scope"> <slot :name="column.slot_name" :row="scope.row"></slot> </template> </el-table-column> <el-table-column :key="key" :prop="column.prop" :label="column.label" :width="column.width" v-else-if="!column.hide" > </el-table-column> </template> </el-table> </div> </template> <script> export default { name: "H3yunTableCompV1", data() { return { // 表格对象 -- 1 tableObj: { columns: [] }, tableData: [{ id: 1, title: '标题1', date: '2016-05-02', name: '王小虎', address: '上海市普陀区金沙江路 1518 弄', tag: '家' }, { id: 2, title: '标题2', date: '2016-05-04', name: '王小虎', address: '上海市普陀区金沙江路 1517 弄', tag: '公司' }, { id: 3, title: '标题3', date: '2016-05-01', name: '王小虎', address: '上海市普陀区金沙江路 1519 弄', tag: '家' }] } }, // 接收父组件传递过来的值 props: { // 接收父组件传递过来的data数据,类型为Object -- 2 data: Object }, watch: { // 监控父组件中的data,保证子组件中的tableObj与父组件一致 -- 3 data: { deep: true, // 深度监控 immediate: true, // 在组件创建时立即触发 handler(newVal, oldVal) { this.init(newVal) // 初始化 } } }, methods: { handleSelectionChange(val) { this.multipleSelection = val; }, // 初始化方法 -- 4 init(newVal) { for (const key in newVal) { // 如果父组件传的值能与tableObj的属性匹配,比如父子组件都有tableObj.columns,则会进入这个if if (Object.keys(this.tableObj).includes(key)) { // 比如:tableObj.columns = newVal.columns this.tableObj[key] = newVal[key] } } } } } </script> <style scoped> </style>
父组件使用template
的v-slot:插槽名
去处理插槽。这里是拿到了整行数据而不仅仅是title这一列,里面的内容完全是自定义的。
<H3yunTableCompV1 :data="tableObj"> // 处理标题插槽 <template v-slot:title_slot="scope"> <el-link type="primary">{{ scope.row.title }}</el-link> </template> </H3yunTableCompV1> export default { components: { H3yunTableCompV1 }, data() { return { // 这个对象可以从后端获取,下面是一些示例数据 tableObj: { // 数据列 - 即el-table-column组件中的属性 columns: [ {prop: 'title', label: '标题', width: '180', type: 'slot', slot_name: 'title_slot'}, // 定义标题列是插槽 {prop: 'date', label: '日期', width: '180'}, {prop: 'name', label: '名字', width: '180'}, {prop: 'address', label: '地址', width: '180'} ] } } } }
注意:插槽 - 按钮这个示例是在上一个示例的基础上的。
效果如下:
增加列,并定义插槽的名称为operate_slot
{prop: 'operate', label: '操作', width: '180', type: 'slot', slot_name: 'operate_slot'}
插槽处理
<H3yunTableCompV1 :data="tableObj">
// 标题 - 插槽
<template v-slot:title_slot="scope">
<el-link type="primary">{{ scope.row.title }}</el-link>
</template>
// 操作 - 插槽
<template v-slot:operate_slot="scope">
<el-button-group>
<el-button type="primary" disabled>编辑</el-button>
<el-button type="primary" disabled>删除</el-button>
</el-button-group>
</template>
</H3yunTableCompV1>
效果如下:
代码改动比较多,下面直接上代码。
父组件如下,主要增加与后端联动。
<template> <div class="container" style="min-height: 100%; padding-bottom: 100px;"> <H3yunTableCompV1 :data="tableObj"> // 标题 - 插槽 <template v-slot:fnsku_slot="scope"> <el-link type="primary">{{ scope.row.fnsku }}</el-link> </template> // 操作 - 插槽 <template v-slot:operate_slot="scope"> <el-button-group> <el-button type="primary" disabled>编辑</el-button> <el-button type="primary" disabled>删除</el-button> </el-button-group> </template> </H3yunTableCompV1> </div> </template> <script> import H3yunTableCompV1 from "../../components/table/H3yunTableCompV1"; export default { props: [], components: { H3yunTableCompV1 }, data() { return { // 这个对象可以从后端获取,下面是一些示例数据 tableObj: { http: { // 这个url你们需要写成完整的url url: '/logisticSalesPrediction/list', params: {}, // url返回结果的数据结构, result: { // 表格内容表示是在result.records中获取 list: 'records', // 数据量总数是在result.total中获取 total: 'total' } }, pageNum: 1, pageSize: 10, total: 0, // 数据列 - 即el-table-column组件中的属性 columns: [ {prop: 'fnsku', label: 'fnsku', width: '180', type: 'slot', slot_name: 'fnsku_slot'}, // 定义标题列是插槽 {prop: 'isSeason', label: '是否是时令性产品', width: '180'}, {prop: 'activityIncrement', label: '活动增量', width: '180'}, {prop: 'prediction', label: '销量预测', width: '180'}, ] } } }, methods: {}, } </script> <style scoped> .container { } </style>
下面是子组件的代码。
首先,在table标签下面增加了分页组件,其次增加了axios的请求,与响应结果的处理。细节部分呢,就是切换页码,页大小和序号。
<template> <div> <el-table ref="multipleTable" tooltip-effect="dark" style="width: 100%" :data="tableData" @selection-change="handleSelectionChange" > <!--多选--> <el-table-column type="selection" width="55"> </el-table-column> <!--序号--> <el-table-column type="index" :index="calIndex" > </el-table-column> <!--插槽处理--> <template v-for="(column,key) in tableObj.columns"> <el-table-column :key="key" :prop="column.prop" :label="column.label" :width="column.width" v-if="column.type == 'slot'" > <template slot-scope="scope"> <slot :name="column.slot_name" :row="scope.row"></slot> </template> </el-table-column> <el-table-column :key="key" :prop="column.prop" :label="column.label" :width="column.width" v-else-if="!column.hide" > </el-table-column> </template> </el-table> <div> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="tableObj.pageNum" :page-sizes="[10, 20, 50, 100]" :page-size="tableObj.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="tableObj.total"> </el-pagination> </div> </div> </template> <script> import request from "../../utils/request"; export default { name: "H3yunTableCompV1", data() { return { // 表格对象 -- 1 tableObj: { http: { url: undefined, params: {}, result: { list: undefined, total: undefined } }, pageNum: 1, pageSize: 10, total: 0, columns: [] }, tableData: [] } }, // 接收父组件传递过来的值 props: { // 接收父组件传递过来的data数据,类型为Object -- 2 data: Object }, watch: { // 监控父组件中的data,保证子组件中的tableObj与父组件一致 -- 3 data: { deep: true, // 深度监控 immediate: true, // 在组件创建时立即触发 handler(newVal, oldVal) { this.init(newVal) // 初始化 } } }, // 挂载之前加载数据 beforeMount() { this.load() }, methods: { // 计算序号 calIndex(index) { return (this.tableObj.pageNum - 1) * (this.tableObj.pageSize) + index + 1 }, // 构建查询参数 buildParams() { const params = this.tableObj.http.params params.pageNum = this.tableObj.pageNum params.pageSize = this.tableObj.pageSize return params }, // 解析构建结果 - 为了适配 list: 'data.records',做一下处理 buildResult(data, key) { const keys = key.split('.') let res = data for (const key of keys) { res = res[key] } return res }, // 加载后端数据 load() { // request对axios进行了一层封装 request.post(this.tableObj.http.url, this.buildParams()).then(pageObj => { // 后端返回结果,需要的字段在哪不写死 this.tableData = this.buildResult(pageObj, this.tableObj.http.result.list) this.tableObj.total = this.buildResult(pageObj, this.tableObj.http.result.total) }) }, // 更改每页数量 handleSizeChange(val) { this.tableObj.pageSize = val this.tableObj.pageNum = 1 this.load() }, // 页码切换 handleCurrentChange(val) { this.tableObj.pageNum = val this.load() }, // 多选 handleSelectionChange(val) { this.multipleSelection = val; }, // 初始化方法 -- 4 init(newVal) { for (const key in newVal) { // 如果父组件传的值能与tableObj的属性匹配,比如父子组件都有tableObj.columns,则会进入这个if if (Object.keys(this.tableObj).includes(key)) { // 比如:tableObj.columns = newVal.columns this.tableObj[key] = newVal[key] } } } } } </script> <style scoped> </style>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。