Vue+ElementUI 实现 动态调整表格列 显示隐藏&显示顺序

18,100 阅读3分钟

小知识,大挑战!本文正在参与「程序员必备小知识」创作活动

本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。

先来看一个需求

1.表格可多选

2.表格可排序

3.表格可拖动列宽

4.表格固定列和表头

5.表格列顺序可调整

6.表格列可隐藏或显示

7.表格设置需要实时保存

 

解决思路

其中[1、2、3、4 ] Element-UI table组件原生就支持的

[5] 列顺序可调整 可以通过 改变 el-table-column 的渲染顺序实现

[6] 可以通过控制 el-table-column 的展示与隐藏实现

[7] 将每次修改存至本地localStorage

 

Table组件 地址:element.eleme.io/#/zh-CN/com…

 

上代码:

核心在于需要循环渲染 el-table-column

<template>部分

<!--列设置按钮-->
<el-dropdown trigger="click">
  <el-button icon="el-icon-s-operation" size="mini">列设置</el-button>
  <el-dropdown-menu slot="dropdown">
    <span class="title">列设置</span>
    <el-tree draggable :data="columns" :props="defaultProps" :allow-drop="allowDrop" @node-drop="handleDrop">
      <span class="tree-table-setting" slot-scope="{ node, data }">
        <el-switch @change="saveTableColumns" v-model="data.show"> </el-switch>
        <span>{{ node.label }}</span>
      </span>
    </el-tree>
  </el-dropdown-menu>
</el-dropdown>


<!--表格-->
<div>
  <el-table
    :key="tableKey"
    :data="tableData"
    :height="tableHeight"
    :row-style="{ height: '40px' }"
    :cell-style="{ borderRight: 'none' }"
    :header-cell-style="{ height: '40px', padding: 0, background: '#f6f8fa', color: '#333' }"
    @row-click="handelTableClick"
    @selection-change="handleSelectionChange"
    @header-dragend="surverWidth"
    border
    size="mini"
    tooltip-effect="dark"
    highlight-current-row
  >
    <el-table-column align="center" type="selection"> </el-table-column>
    <template v-for="item in columns">
      <el-table-column
        v-if="item.show"
        show-overflow-tooltip
        :prop="item.prop"
        :sortable="item.sortable"
        :label="item.label"
        :width="item.width"
        :key="item.prop"
        :resizable="item.resizable"
      >
        <template slot-scope="scope">
          <span v-if="item.prop === 'clue_type'">{{ scope.row[item.prop] | clueType }}</span>
          <span v-else-if="item.prop === 'clue_source'">{{ scope.row[item.prop] | clueSource }}</span>
          <span v-else-if="item.prop === 'contact_type'">{{ scope.row[item.prop] | commonType }}</span>
          <span v-else-if="item.prop === 'company_name'" class="link">{{ scope.row[item.prop] }}</span>
          <span v-else>{{ scope.row[item.prop] }}</span>
        </template>
      </el-table-column>
    </template>
    <!-- 固定列 -->
    <el-table-column fixed="right" label="关注" width="56">
      <template slot-scope="scope">
        <el-button
          style="height: 10px;padding:0; margin:0;"
          type="text"
          @click.native.stop="clueTableRowClick(scope.row, 'collect')"
          size="mini"
        >
          <img v-if="scope.row.collect === 1" style="width:16px" src="@/assets/star1.png" />
          <img v-else style="width:16px" src="@/assets/star0.png" />
        </el-button>
      </template>
    </el-table-column>
    <el-table-column fixed="right" label="编辑" width="56">
      <template slot-scope="scope">
        <el-button
          style="height: 10px;padding:0; margin:0;"
          type="text"
          @click.native.stop="clueTableRowClick(scope.row, 'edit')"
          size="mini"
        >
          <img style="width:16px" src="@/assets/edit.png" />
        </el-button>
      </template>
    </el-table-column>
    <el-table-column> </el-table-column>
  </el-table>
</div>

注意事项

1.控制el-table-column显示与隐藏使用v-show无效,需要使用v-if。

2.部分列需要使用过滤器 我这里使用了if做判断。

3.由于虚拟Dom算法导致有时表格并不会实时刷新,这里需要给table添加key值。

4.列设置中可上下拖动采用 Tree组件。

5.由于需要固定列和表头 每次获取到表格数据后,再给tableHight赋值。

const winHeight = document.body.clientHeight
// 窗口大小 - 表格顶部高度
this.tableHeight = winHeight - 260

6.这里由于给row绑定了click事件,需要给row中的Button按钮添加.native修饰,防止事件冒泡添加.stop修饰。

 

<script>部分

export default {
  data() {
    // 表格key
    tableKey: 1,
    // 表格数据
    tableData: [],
    // 默认表格高度
    tableHeight:600// 表格展示项配置
    columns:[
      {
        prop: 'name', // 对应列内容的字段名
        label: '姓名', // 显示的标题
        width: 66, // 对应列的宽度
        resizable: true, // 对应列是否可以通过拖动改变宽度(需要在 el-table 上设置 border 属性为真)
        show: true, // 展示与隐藏
        sortable: false // 对应列是否可以排序
      },
      {
        prop: 'clue_type',
        label: '线索类型',
        width: 78,
        resizable: true,
        show: true,
        sortable: false
      },
      // ... 省略部分字段
    ],
    // 列设置中 tree配置
    defaultProps: {
      children: 'children',
      label: 'label'
    }
  },
  mounted(){
    this.init()
  },
  methods: {
    init() {
      // 判断本地是否有表格配置数据 ? 加载 : 忽略
      // 获取表格数据
      // 重设表格高度
    },
    allowDrop(draggingNode, dropNode, type) {
      // 仅允许Tree节点上下拖动
      return type !== 'inner'
    },
    // Tree 拖动时更新表格
    handleDrop() {
      this.tableKey++
      // 保存表格配置
      this.saveTableColumns()
    },
    // 重置表格列设置
    resetTable() {
      // ... 忽略
    },
    // 显示隐藏切换 && 保存表格配置
    saveTableColumns() {
      // setStorage 封装了 localStorage
      setStorage('clueTable', this.columns)
    },
    // 选中表格行
    handelTableClick(row) {
      // ... 省略业务逻辑
    },
    // table多选操作
    handleSelectionChange(val) {
      // ... 省略业务逻辑
    },
    // 表头拖动事件
    surverWidth(newWidth, oldWidth, column, event) {
      this.columns = this.columns.map(v => {
        if (v.prop === column.property) v.width = newWidth
        return v
      })
      this.saveTableColumns()
    },
    // 关注与编辑操作
    clueTableRowClick(val, type) {
      // ... 省略业务逻辑
    }
  }
}

 


 以上就是该需求的简单实现。

END

「欢迎在评论区讨论,掘金官方将在掘力星计划活动结束后,在评论区抽送100份掘金周边,抽奖详情见活动文章」。