element-ui table 表格的列显示/隐藏、列拖动、列的宽度拖动数据保存 2(仅适用于新手)
1.紧接着上一章(感觉进度有点慢,讲快一点咯):在utils下新建文件UT.js(此文件是工具文件),然后在main.js里面引入一下,这样全局都可以使用了:
UT.js代码如下:
// 此文件是工具类
export default{
/**
* 深度拷贝对象
* @param obj 要拷贝的对象
* @returns obj-返回一个新的对象
*/
scopy(obj){
return JSON.parse(JSON.stringify(obj));
},
}
main.js代码如下:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 全局样式表
import '@/styles/index.less';
// 引入element-ui所需组件
import '@/utils/elementui.js';
// 引入公共工具js
import UT from '@/utils/UT';
Vue.prototype.U = UT;
Vue.config.productionTip = false;
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
2.在views下新建文件夹mixins(此文件夹是专门存放混入的文件,不懂混入的可以去官网查看),在其中新建文件TableDataSet.js(里面我们存放初始化数据方法、子组件改变数据后需要向父组件传入数据的函数),代码如下:
export default {
methods: {
/**
* 这个方法是子组件数据改变后,需要向父组件传入数据(即父组件接收数据)的函数
* @param {*} e 这个对象里面包含{dgName: 表格数据对象名称, cols: 已被修改后的列数组 }
*/
saveTbSet(e) {
const that = this;
// 重新为当前显示列数组赋值(此处深度拷贝一下,防止改变原来的对象)
that[e.dgName].columns = that.U.scopy(e.cols);
// 这里使用$nextTick是因为改变数据后相当于重新渲染列,会导致表格列错位,用这个方法防止错位
// 可以尝试去掉看看效果
that.$nextTick(() => {
// 使用表格的doLayout方法可以重新渲染,防止列错位
that.$refs[that[e.dgName].tbName].doLayout();
});
},
/**
* 初始化-表格设置数据
* @param {*} dgName 表格数据对象名称(为啥一直带着这个名称,目的是为了通用)
* 这个函数需要在每个表格组件的created钩子中调用
*/
initTbSetData(dgName) {
const that = this;
// 目前我们不涉及后台,暂时将用户设置的数据保存至缓存中
let tbSet = sessionStorage.getItem(that[dgName].tbName);
if(tbSet){
// 如果缓存中存在用户设置的数据,则将字符串数据转换成json对象
let cols = JSON.parse(tbSet);
// 生成表格当前显示列的数组数据,即从保存数据中去除show属性为true的列
let list = cols.filter(it => {return it.show;});
// 重新为当前显示列数组赋值
that[dgName].columns = list;
}else{
// 如果缓存中不存在用户设置的数据,直接为最原始的列数组中每个对象添加show属性,并且值为true,因为默认所有列都显示
that[dgName].srcCols.forEach(it => { it.show = true; });
// 重新为当前显示列数组赋值(很多地方都用到深度拷贝对象,为的防止修改数据时修改到了原来的数据,这点很重要,不然之后的拖动列会出现错位)
that[dgName].columns = that.U.scopy(that[dgName].srcCols);
}
},
},
}
然后我们在UserList组件中引入此混入文件,如下图所示(这样,就可以在UserList组件中的created钩子中调用初始化方法了):
3.现在我们需要修改UserList组件:
3.1 创建一个表格数据对象,组件的data如下代码:
data() {
let cols = [
{label: '日期', field: 'date', width: 130},
{label: '姓名', field: 'name', width: 130},
{label: '地址', field: 'address', width: 'auto'},
];
return {
dg: {
// 当前表格数据对象名称(此名称应该是当前组件唯一)
dgName: 'dg',
// 当前表格的ref名称(此名称应该是唯一)
tbName: 'userListTb',
// 表格显示的数据
list: [],
// 原始的列数组(会传入组件,重置时会用上)
srcCols: cols,
// 当前表格显示的所有列
columns: [],
// 查询参数对象
ps: {}
},
}
}
3.2 在created组件钩子函数中,初始化一些数据,如下:
const that = this;
let list = [{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-08',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-06',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-07',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}];
that.dg.list = list;
that.initTbSetData(that.dg.dgName);
3.3 在组件html中修改一下,即循环遍历列数组,生成列,代码如下:
<el-table
:ref="dg.tbName"
:data="dg.list"
row-key="id"
border fit
height="250"
>
<el-table-column fixed="left" type="selection" width="40"></el-table-column>
<el-table-column
v-for="col in dg.columns"
:key="col.field"
:class-name="dg.dgName"
:prop="col.field"
:label="col.label"
:width="col.width"
></el-table-column>
</el-table>
3.4 引入子组件,代码如下(@saveSet 这是子组件数据改变后,通过这个函数传入数据给父组件(这个不懂可以看看官网的父子组件通信),剩下的参数在TableSet组件中有说明):
<TableSet
:dgName="dg.dgName"
:tbId="dg.tbName"
:srcCols="dg.srcCols"
:columns="dg.columns"
@saveSet="saveTbSet"
/>
UserList组件的完全代码如下:
<!-- 用户列表 -->
<template>
<div class="user-list">
<div class="tb-tools">
<el-button type="primary">添加</el-button>
<el-button type="success">删除</el-button>
<TableSet
:dgName="dg.dgName"
:tbId="dg.tbName"
:srcCols="dg.srcCols"
:columns="dg.columns"
@saveSet="saveTbSet"
/>
</div>
<el-table
:ref="dg.tbName"
:data="dg.list"
row-key="id"
border fit
height="250"
>
<el-table-column fixed="left" type="selection" width="40"></el-table-column>
<el-table-column
v-for="col in dg.columns"
:key="col.field"
:class-name="dg.dgName"
:prop="col.field"
:label="col.label"
:width="col.width"
></el-table-column>
</el-table>
</div>
</template>
<script>
import TableDataSet from '@/views/mixins/TableDataSet'
import TableSet from '@/components/TableSet';
export default {
name: 'UserList',
mixins: [ TableDataSet ],
components: { TableSet },
data() {
let cols = [
{label: '日期', field: 'date', width: 130},
{label: '姓名', field: 'name', width: 130},
{label: '地址', field: 'address', width: 'auto'},
];
return {
dg: {
// 当前表格数据对象名称(此名称应该是当前组件唯一)
dgName: 'dg',
// 当前表格的ref名称(此名称应该是唯一)
tbName: 'userListTb',
// 表格显示的数据
list: [],
// 原始的列数组(会传入组件,重置时会用上)
srcCols: cols,
// 当前表格显示的所有列
columns: [],
// 查询参数对象
ps: {}
},
}
},
created() {
const that = this;
let list = [{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-08',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-06',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-07',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}];
that.dg.list = list;
that.initTbSetData(that.dg.dgName);
},
methods:{
},
}
</script>
<style lang="less" scoped>
.user-list{
// 表格顶部工具栏
.tb-tools{
padding: 5px;
background: #fff;
position: relative;
// 表格个性设置
.tb-set{
position: absolute;
bottom: 10px;
right: 10px;
i{
cursor: pointer;
}
}
}
}
</style>
4.TableSet组件也需要做一些修改,完整代码如下:
<!-- 表格设置 -->
<template>
<div class="table-set" title="表格个性设置">
<el-popover
placement="left"
width="100"
trigger="click">
<div class="tb-cols">
<div class="btns">
<el-button-group>
<el-button title="重置" type="primary" icon="el-icon-refresh-right">重置</el-button>
<el-button title="保存" type="primary" icon="el-icon-check">保存</el-button>
</el-button-group>
</div>
<div class="col-items">
<el-checkbox
v-for="col in fields"
:key="col.field"
:label="col.label"
border
:disabled="col.disabled ? true : false"
v-model="col.show"
></el-checkbox>
</div>
</div>
<i class="el-icon-s-tools" slot="reference"></i>
</el-popover>
</div>
</template>
<script>
export default {
name: 'TableSet',
props: {
// 表格数据参数对象名称
dgName: {
require: true,
type: String,
default: "dg",
},
// 表格唯一名称
tbId: {
require: true,
type: String,
default: "",
},
// 表格列原始数组
srcCols: {
require: true,
type: Array,
default: [],
},
// 表格当前显示列数组
columns: {
require: true,
type: Array,
default: [],
},
},
data() {
return {
// 保存原始的列数据(主要是为了第一次和重置表格列的时候使用)
oldCols: this.U.scopy(this.srcCols),
// 当前表格所有显示列数组(需要传到父组件表格显示)
cols: this.U.scopy(this.columns),
// 表格原所有列数组(包含所有列,只是show属性的值变化来隐藏/显示列)
fields: this.U.scopy(this.columns)
}
},
watch: {
// 监控-当前列的数据变动
fields: {
handler(arr){
const that = this;
let cols = that.U.scopy(arr);
let list = cols.filter((it) => { return it.show; });
if(list.length < 1) {
alert('列表至少需保留一列');
}else{
that.$emit("saveSet", { dgName: that.dgName, cols: list });
}
},
deep: true // true=深度监听
}
},
methods:{
},
}
</script>
<style lang="less" scope>
.table-set{
position: absolute;
right: 8px;
bottom: 5px;
cursor: pointer;
}
.tb-cols{
line-height: 35px;
// 显示列的最大高度为浏览器可视区域的60%
max-height: 60vh;
// 当表格列太多的时候,超过了最大高度,则自动显示滚动条
overflow-y: auto;
// 隐藏横向的滚动条
overflow-x: hidden;
.btns{
.el-button-group{
display: flex;
// 按钮组下所有按钮宽度一样
button{
flex: 1;
}
}
}
.col-items{
& > label{
margin: 0px !important;
width: 100%;
}
}
}
</style>
页面效果图如下:
注意点
1.比前几章要快点,基本都是贴代码,如果新手有什么不懂的可以留言一起探讨探讨;
2.新手还是建议少复制,多敲,自己敲出来的总要好那么一点;
3.下一章讲一讲如何通过sortablejs插件实现拖动列改变列的顺序;
活到老,学到老,学无止尽!欢迎大家相互讨论,相互学习!不喜勿喷!