vue2+element-ui 记录7

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插件实现拖动列改变列的顺序;

活到老,学到老,学无止尽!欢迎大家相互讨论,相互学习!不喜勿喷!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值