优雅的将ElementUI表格变身成树形表格的方法步骤


Posted in Javascript onApril 11, 2019

由于ElementUI目前还未开发树形表格组件,也参阅了网络上部分基于ElementUI表格封装的开源树形组件,如果想进行二次开发的话都不太理想,所以就萌生了自行开发树形表格。

本示例提供开发思路,移除了多余的样式,比较适合新手入门学习,如果应用于实际项目还请自行封装。

目前还仅仅实现了视觉的树结构的层级效果和控制结构的显示隐藏,后续还会进行不断的完善和优化,有必要的话会对组件进行二次封装,有点在重复造论的感觉哈。

效果图

优雅的将ElementUI表格变身成树形表格的方法步骤

完整代码

页面(tree-table.vue)

<template>
 <div>
  TreeTable
  <el-table :data="list" :row-style="tableRowStyle" border>
   <el-table-column type="selection" width="55"></el-table-column>
   <el-table-column prop="id" label="ID" width="180">
    <template slot-scope="scope">
     <span class="collapse"
        :class="collapseClass(scope.row)"
        :style="tableRowPaddingStyle(scope.row)"
        @click="handleCollapseClick(scope.row)">
     </span>
     <span>{{ scope.row.id }}</span>
    </template>
   </el-table-column>
   <el-table-column prop="name" label="NAME"></el-table-column>
  </el-table>
 </div>
</template>

<script lang="ts">
  import {Component, Vue} from 'vue-property-decorator'
  // 引入两个封装好的工具方法
  import { arrayToTree } from './utils/array.js'
  import { ergodicTree } from './utils/tree.js'

  @Component
  export default class TreeTable extends Vue {
    private list: object[] = [];
    private tree: object[] = [];

    created() {
      // 准备一组含有父子级关系的一维数组方便示例测试
      // 在实际项目应用中,理应通过后端接口返回
      let _list = [
        {
          id: 'a',
          pid: '',
          name: '部门a',
          children: []
        },
        {
          id: 'a1',
          pid: 'a',
          name: '子部门a1',
          children: []
        },
        {
          id: 'a2',
          pid: 'a',
          name: '子部门a2',
          children: []
        },
        {
          id: 'a2-1',
          pid: 'a2',
          name: '子部门a2-1',
          children: []
        },
        {
          id: 'a2-2',
          pid: 'a2',
          name: '子部门a2-2',
          children: []
        },
        {
          id: 'a3',
          pid: 'a',
          name: '子部门a3',
          children: []
        },
        {
          id: 'a3-1',
          pid: 'a3',
          name: '子部门a3-1',
          children: []
        },
        {
          id: 'b',
          pid: '',
          name: '部门b',
          children: []
        },
        {
          id: 'b1',
          pid: 'b',
          name: '子部门b1',
          children: []
        },
        {
          id: 'c',
          pid: '',
          name: '部门c',
          children: []
        },
      ];
      
      // 将一维数组转成树形结构并存储于tree变量
      this.tree = arrayToTree(_list);
      
      // 考虑到实际应用过程中接口返回的数据是无序的,所以我们对tree进行先序遍历将节点一一插入到list变量
      this.list = [];
      ergodicTree(this.tree, (node: any) => {
        this.list.push(node);
        
        // 遍历过程中并对每个节点挂载open和show属性
        // open:控制节点的打开和关闭
        // show:控制节点的显示和隐藏
        this.$set(node, 'open', true);
        this.$set(node, 'show', true)
      })
    }

    // 控制行的显示和隐藏
    tableRowStyle(scope: any) {
      return {
        'display': scope.row.show ? '' : 'none'
      }
    }

    // 通过每个节点的深度,设置行的缩进实现视觉上的层级效果
    tableRowPaddingStyle(row: any) {
      return {
        'margin-left': `${(row._depth - 1) * 24}px`
      }
    }

    // 控制展开按钮的展开和关闭状态
    collapseClass(row: any) {
      return {
        'collapse--open': row.open == false && row.children && row.children.length > 0,
        'collapse--close': row.open == true && row.children && row.children.length > 0
      }
    }

    // 处理展开按钮的点击事件
    handleCollapseClick(row: any) {
      const _open = row.open;
      // 通过节点访问路径控制节点的显示隐藏,由于内存指针的关系list和tree的节点操作都会相互影响
      ergodicTree(this.tree, (node: any) => {
        node._idPath.forEach((pathId: any) => {
          if (pathId == row.id) {
            this.$set(node, 'show', !_open);
            this.$set(node, 'open', !_open)
          }
        })
      });
      row.show = true;
      row.open = !_open;
    }
  }
</script>

<style lang="scss" scoped>
 .collapse {
  display: inline-block;
  width: 8px;
  cursor: pointer;
  margin-right: 8px;
 }

 .collapse--open:before {
  content: '+';
 }

 .collapse--close:before {
  content: '-';
 }
</style>

工具方法

考虑数组转树和遍历树都是在实际项目中都是非常常用的,所以这边对这两个方法进行了封装。

数组转树结构(./utils/array.ts)

export function arrayToTree(list: object[], props = {id: 'id', pid: 'pid', children: 'children'}) {
      let tree: object[] = [];
      let map: any = {};

      let listLength = list.length;
      for (let i = 0; i < listLength; i++) {
        let node: any = list[i];
        let nodeId: any = node[props.id];
        map[nodeId] = node;
      }

      for (let i = 0; i < listLength; i++) {
        let node: any = list[i];
        let nodePid: any = node[props.pid];
        let parentNode: any = map[nodePid];
        if (parentNode) {
          parentNode[props.children] = parentNode[props.children] || [];
          parentNode[props.children].push(node)
        } else {
          tree.push(node)
        }
      }

      return tree
    }

遍历树结构(./utils/tree.ts)

结合实际项目应用,我们采用了先序遍历法对树进行遍历,为了方便在业务代码里的应用,在遍历过程中会对每个节点挂载节点访问路径 _idPath 属性和节点深度 _depth 属性。

export function ergodicTree(tree: object[], callback: any = () => {}, props = {id: 'id', pid: 'pid', children: 'children'}) {
      function _ergodicTree(tree: object[], parentIdPath?: any[], depth: number = 0) {
        const treeLength = tree.length;
        for (let i = 0; i < treeLength; i++) {
          let node: any = tree[i];
          const _idPath: any[] = parentIdPath ? [...parentIdPath, node[props.id]] : [node[props.id]];
          const _depth: number = depth + 1;
          node._idPath = _idPath;
          node._depth = _depth;
          callback(node);
          if (node[props.children] && node[props.children] instanceof Array) {
            _ergodicTree(node[props.children], _idPath, _depth)
          }
        }
      }

      _ergodicTree(tree);
      return tree;
    }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
一个很简单的办法实现TD的加亮效果.
Jun 29 Javascript
JavaScript的类型转换(字符转数字 数字转字符)
Aug 30 Javascript
在JavaScript里嵌入大量字符串常量的实现方法
Jul 07 Javascript
jQuery中unwrap()方法用法实例
Jan 16 Javascript
jQuery设置Cookie及删除Cookie实例分析
Apr 15 Javascript
bootstrap插件treeview实现全选父节点下所有子节点和反选功能
Jul 21 Javascript
vue+element-ui动态生成多级表头的方法
Aug 28 Javascript
详解Vue CLI3配置之filenameHashing使用和源码设计使用和源码设计
Aug 31 Javascript
微信小程序内拖动图片实现移动、放大、旋转的方法
Sep 04 Javascript
使用electron将vue-cli项目打包成exe的方法
Sep 29 Javascript
Vue.js 事件修饰符的使用教程
Nov 01 Javascript
vuecli3.x中轻松4步带你使用tinymce的步骤
Jun 25 Javascript
详解用场景去理解函数柯里化(入门篇)
Apr 11 #Javascript
Vue开发Html5微信公众号的步骤
Apr 11 #Javascript
跟混乱的页面弹窗说再见
Apr 11 #Javascript
vue实现todolist功能、todolist组件拆分及todolist的删除功能
Apr 11 #Javascript
vue实现todolist基本功能以及数据存储功能实例详解
Apr 11 #Javascript
JavaScript高阶教程之“==”隐藏下的类型转换
Apr 11 #Javascript
使用Vue父子组件通信实现todolist的功能示例代码
Apr 11 #Javascript
You might like
动态网站web开发 PHP、ASP还是ASP.NET
2006/10/09 PHP
PHPShop存在多个安全漏洞
2006/10/09 PHP
如何开发一个虚拟域名系统
2006/10/09 PHP
基于PHP 面向对象之成员方法详解
2013/05/04 PHP
ThinkPHP写数组插入与获取最新插入数据ID实例
2014/11/03 PHP
PHP实现远程下载文件到本地
2015/05/17 PHP
php中的常用魔术方法汇总
2016/02/14 PHP
PHP构造函数与析构函数用法示例
2016/09/28 PHP
刷新页面实现方式总结(HTML,ASP,JS)
2008/11/13 Javascript
加速IE的Javascript document输出的方法
2010/12/02 Javascript
jquery动画2.元素坐标动画效果(创建一个图片走廊)
2012/08/24 Javascript
js使用DOM设置单选按钮、复选框及下拉菜单的方法
2015/01/20 Javascript
基于jQuery滑动杆实现购买日期选择效果
2015/09/15 Javascript
Javascript中的arguments对象
2016/06/20 Javascript
BootStrap Validator 版本差异问题导致的submitHandler失效问题的解决方法
2016/12/01 Javascript
最常见和最有用的字符串相关的方法详解
2017/02/06 Javascript
从零开始学习Node.js系列教程五:服务器监听方法示例
2017/04/13 Javascript
使用jQuery实现简单的tab框实例
2017/08/22 jQuery
vue2单元测试环境搭建
2018/05/24 Javascript
vue 父组件通过$refs获取子组件的值和方法详解
2019/11/07 Javascript
Python基于分析Ajax请求实现抓取今日头条街拍图集功能示例
2018/07/19 Python
对pandas写入读取h5文件的方法详解
2018/12/28 Python
对Python中DataFrame选择某列值为XX的行实例详解
2019/01/29 Python
python 爬虫百度地图的信息界面的实现方法
2019/10/27 Python
python多线程使用方法实例详解
2019/12/30 Python
python求一个字符串的所有排列的实现方法
2020/02/04 Python
Python Selenium XPath根据文本内容查找元素的方法
2020/12/07 Python
TripAdvisor土耳其网站:全球知名旅行社区,真实旅客评论
2017/04/17 全球购物
美国娱乐和流行文化商品店:FYE
2017/09/14 全球购物
德国团购网站:Groupon德国
2018/03/13 全球购物
香港最大的洋酒零售连锁店:屈臣氏酒窖(Watson’s Wine)
2018/12/10 全球购物
入党自我评价范文
2014/02/02 职场文书
毕业生工作求职信
2014/06/30 职场文书
团队合作精神学习心得体会
2016/01/19 职场文书
工作总结之小学教师体育工作范文(3篇)
2019/10/07 职场文书
MySQL中order by的执行过程
2022/06/05 MySQL