详解vue-cli+element-ui树形表格(多级表格折腾小计)


Posted in Javascript onApril 17, 2019

前沿

最近在项目开发中需要做一个多级表格,树形表格的功能,看看element-ui上没有,自己开是折腾,话不多说,上思路和代码。

效果图:

详解vue-cli+element-ui树形表格(多级表格折腾小计)

可点击收缩,展开。

一,首先创建一个公共的文件夹treeTable,里边放一个index.vue和eval.js

先看看index.vue,原理就是在element-ui的基础上做了进一步改造。

//利用element-ui的 <template slot-scope="scope">属性,在插入多级表格
<template>
 <el-table :data="formatData" :row-style="showRow" v-bind="$attrs">
  <el-table-column v-if="columns.length===0" width="150">
   <template slot-scope="scope">
    <span v-for="space in scope.row._level" class="ms-tree-space" :key="space"></span>
    <span class="tree-ctrl" v-if="iconShow(0,scope.row)" @click="toggleExpanded(scope.$index)">
     <i v-if="!scope.row._expanded" class="el-icon-plus"></i>
     <i v-else class="el-icon-minus"></i>
    </span>
    {{scope.$index}}
   </template>
  </el-table-column>
  <el-table-column v-else v-for="(column, index) in columns" :key="column.value" :label="column.text" :width="column.width">
   <template slot-scope="scope">
    <span v-if="index === 0" v-for="space in scope.row._level" class="ms-tree-space" :key="space"></span>
    <span class="tree-ctrl" v-if="iconShow(index,scope.row)" @click="toggleExpanded(scope.$index)">
     <i v-if="!scope.row._expanded" class="el-icon-plus"></i>
     <i v-else class="el-icon-minus"></i>
    </span>
    {{scope.row[column.value]}}
   </template>
  </el-table-column>
  <slot></slot>
 </el-table>
</template>

<script>
import treeToArray from './eval'
export default {
 name: 'treeTable',
 props: {
  data: {
   type: [Array, Object],
   required: true
  },
  columns: {
   type: Array,
   default: () => []
  },
  evalFunc: Function,
  evalArgs: Array,
  expandAll: {
   type: Boolean,
   default: false
  }
 },
 computed: {
  // 格式化数据源
  formatData: function() {
   let tmp
   if (!Array.isArray(this.data)) {
    tmp = [this.data]
   } else {
    tmp = this.data
   }
   const func = this.evalFunc || treeToArray
   const args = this.evalArgs ? Array.concat([tmp, this.expandAll], this.evalArgs) : [tmp, this.expandAll]
   return func.apply(null, args)
  }
 },
 methods: {
  showRow: function(row) {
   const show = (row.row.parent ? (row.row.parent._expanded && row.row.parent._show) : true)
   row.row._show = show
   return show ? 'animation:treeTableShow 1s;-webkit-animation:treeTableShow 1s;' : 'display:none;'
  },
  // 切换下级是否展开
  toggleExpanded: function(trIndex) {
   const record = this.formatData[trIndex]
   record._expanded = !record._expanded
  },
  // 图标显示
  iconShow(index, record) {
   return (index === 0 && record.children && record.children.length > 0)
  }
 }
}
</script>
<style rel="stylesheet/css">
 @keyframes treeTableShow {
  from {opacity: 0;}
  to {opacity: 1;}
 }
 @-webkit-keyframes treeTableShow {
  from {opacity: 0;}
  to {opacity: 1;}
 }
</style>

<style lang="scss" rel="stylesheet/scss" scoped>
 $color-blue: #2196F3;
 $space-width: 18px;
 .ms-tree-space {
  position: relative;
  top: 1px;
  display: inline-block;
  font-style: normal;
  font-weight: 400;
  line-height: 1;
  width: $space-width;
  height: 14px;
  &::before {
   content: ""
  }
 }
 .processContainer{
  width: 100%;
  height: 100%;
 }
 table td {
  line-height: 26px;
 }

 .tree-ctrl{
  position: relative;
  cursor: pointer;
  color: $color-blue;
  margin-left: -$space-width;
 }
</style>

eval.js

/**
 * @Author: hyf
 * @Date:  2018-10-27
 */
'use strict'
import Vue from 'vue'
export default function treeToArray(data, expandAll, parent = null, level = null) {
  let tmp = []
  Array.from(data).forEach(function(record) {
    if (record._expanded === undefined) {
      Vue.set(record, '_expanded', expandAll)
    }
    let _level = 1
    if (level !== undefined && level !== null) {
      _level = level + 1
    }
    Vue.set(record, '_level', _level)
      // 如果有父元素
    if (parent) {
      Vue.set(record, 'parent', parent)
    }
    tmp.push(record)
    if (record.children && record.children.length > 0) {
      const children = treeToArray(record.children, expandAll, record, _level)
      tmp = tmp.concat(children)
    }
  })
  return tmp
}

二,页面中的用法

<template>
 <div class="app-container">
  <tree-table :data="data" :columns="columns" border></tree-table>
 </div>
</template>

<script>
import treeTable from '@/components/TreeTable'
export default {
 name: 'treeTableDemo',
 components: { treeTable },
 data() {
  return {
   columns: [
    {
     text: '事件',
     value: 'event',
     width: 200
    },
    {
     text: 'ID',
     value: 'id'
    },
    {
     text: '时间线',
     value: 'timeLine'
    },
    {
     text: '备注',
     value: 'comment'
    }
   ],
   data: [
    {
     id: 0,
     event: '事件1',
     timeLine: 50,
     comment: '无'
    },
    {
     id: 1,
     event: '事件1',
     timeLine: 100,
     comment: '无',
     children: [
      {
       id: 2,
       event: '事件2',
       timeLine: 10,
       comment: '无'
      },
      {
       id: 3,
       event: '事件3',
       timeLine: 90,
       comment: '无',
       children: [
        {
         id: 4,
         event: '事件4',
         timeLine: 5,
         comment: '无'
        },
        {
         id: 5,
         event: '事件5',
         timeLine: 10,
         comment: '无'
        },
        {
         id: 6,
         event: '事件6',
         timeLine: 75,
         comment: '无',
         children: [
          {
           id: 7,
           event: '事件7',
           timeLine: 50,
           comment: '无',
           children: [
            {
             id: 71,
             event: '事件71',
             timeLine: 25,
             comment: 'xx'
            },
            {
             id: 72,
             event: '事件72',
             timeLine: 5,
             comment: 'xx'
            },
            {
             id: 73,
             event: '事件73',
             timeLine: 20,
             comment: 'xx'
            }
           ]
          },
          {
           id: 8,
           event: '事件8',
           timeLine: 25,
           comment: '无'
          }
         ]
        }
       ]
      }
     ]
    }
   ]
  }
 }
}
</script>

一下为一些整体思路,以及一些说明,方便后续使用

写在前面

此组件仅提供一个创建TreeTable的解决思路

prop说明

data

必填

原始数据,要求是一个数组或者对象

[{
  key1: value1,
  key2: value2,
  children: [{
   key1: value1
  },
  {
   key1: value1
  }]
 },
 {
  key1: value1
 }]

或者

{
   key1: value1,
   key2: value2,
   children: [{
    key1: value1
   },
   {
    key1: value1
   }]
  }

columns

列属性,要求是一个数组

text: 显示在表头的文字
value: 对应data的key。treeTable将显示相应的value
width: 每列的宽度,为一个数字(可选)

如果你想要每个字段都有自定义的样式或者嵌套其他组件,columns可不提供,直接像在el-table一样写即可,如果没有自定义内容,提供columns将更加的便捷方便

如果你有几个字段是需要自定义的,几个不需要,那么可以将不需要自定义的字段放入columns,将需要自定义的内容放入到slot中,详情见后文

[{
 value:string,
 text:string,
 width:number
},{
 value:string,
 text:string,
 width:number
}]

expandAll
是否默认全部展开,boolean值,默认为false

evalFunc
解析函数,function,非必须
如果不提供,将使用默认的evalFunc

evalArgs
解析函数的参数,是一个数组

请注意,自定义的解析函数参数第一个为this.data,第二个参数为, this.expandAll,你不需要在evalArgs填写。一定记住,这两个参数是强制性的,并且位置不可颠倒 this.data为需要解析的数据,this.expandAll为是否默认展开
如你的解析函数需要的参数为(this.data, this.expandAll,1,2,3,4),那么你只需要将[1,2,3,4]赋值给evalArgs就可以了
如果你的解析函数参数只有(this.data, this.expandAll),那么就可以不用填写evalArgs了

slot

这是一个自定义列的插槽。
默认情况下,treeTable只有一行行展示数据的功能。但是一般情况下,我们会要给行加上一个操作按钮或者根据当行数据展示不同的样式,这时我们就需要自定义列了。
slot和columns属性可同时存在,columns里面的数据列会在slot自定义列的左边展示

其他

如果有其他的需求,请参考el-table的api自行修改index.vue

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

Javascript 相关文章推荐
JavaScript中URL编码函数代码
Jan 11 Javascript
jQuery1.5.1 animate方法源码阅读
Apr 05 Javascript
js实现杯子倒水问题自动求解程序
Mar 25 Javascript
Jquery跳到页面指定位置的方法
May 12 Javascript
jQuery使用andSelf()来包含之前的选择集
May 19 Javascript
JavaScript数据结构和算法之图和图算法
Feb 11 Javascript
简介JavaScript中toUpperCase()方法的使用
Jun 06 Javascript
javascript实现输出指定行数正方形图案的方法
Aug 03 Javascript
jQuery简单动画变换效果实例分析
Jul 04 Javascript
Angularjs中ng-repeat-start与ng-repeat-end的用法实例介绍
Dec 31 Javascript
javascript简单写的判断电话号码实例
May 24 Javascript
jQuery实现定时隐藏对话框的方法分析
Feb 12 jQuery
抖音上用记事本编写爱心小程序教程
Apr 17 #Javascript
基于JS实现web端录音与播放功能
Apr 17 #Javascript
vue-cli的build的文件夹下没有dev-server.js文件配置mock数据的方法
Apr 17 #Javascript
vue component 中引入less文件报错 Module build failed
Apr 17 #Javascript
Vue项目路由刷新的实现代码
Apr 17 #Javascript
vue cli 3.x 项目部署到 github pages的方法
Apr 17 #Javascript
详解vue开发中调用微信jssdk的问题
Apr 16 #Javascript
You might like
POSIX 风格和兼容 Perl 风格两种正则表达式主要函数的类比(preg_match, preg_replace, ereg, ereg_replace)
2010/10/12 PHP
Zend Framework前端控制器用法示例
2016/12/11 PHP
php模仿qq空间或朋友圈发布动态、评论动态、回复评论、删除动态或评论的功能(中)
2017/06/11 PHP
PHP利用Mysql锁解决高并发的方法
2018/09/04 PHP
javascript对象的property和prototype是这样一种关系
2007/03/24 Javascript
JavaScript 事件冒泡简介及应用
2010/01/11 Javascript
js如何获取file控件的完整路径具体实现代码
2013/05/15 Javascript
js动态删除div元素基本思路及实现代码
2014/05/08 Javascript
jquery实现图片随机排列的方法
2015/05/04 Javascript
PHP+MySQL+jQuery随意拖动层并即时保存拖动位置实例讲解
2015/10/09 Javascript
JSONObject使用方法详解
2015/12/17 Javascript
原生JavaScript实现滚动条效果
2020/03/24 Javascript
JS实现响应鼠标点击动画渐变弹出层效果代码
2016/03/25 Javascript
Vue的实例、生命周期与Vue脚手架(vue-cli)实例详解
2017/12/27 Javascript
JS原生带缩略图的图片切换效果
2018/10/10 Javascript
koa大型web项目中使用路由装饰器的方法示例
2019/04/02 Javascript
优化Vue项目编译文件大小的方法步骤
2019/05/27 Javascript
微信小程序吸底区域适配iPhoneX的实现
2020/04/09 Javascript
[50:28]2018DOTA2亚洲邀请赛 3.31 小组赛 A组 Newbee vs KG
2018/04/01 DOTA
构建Python包的五个简单准则简介
2015/06/15 Python
python读取与写入csv格式文件的示例代码
2017/12/16 Python
Python实现的径向基(RBF)神经网络示例
2018/02/06 Python
pandas系列之DataFrame 行列数据筛选实例
2018/04/12 Python
破解安装Pycharm的方法
2018/10/19 Python
详解Python3 基本数据类型
2019/04/19 Python
Python 解析pymysql模块操作数据库的方法
2020/02/18 Python
如何在python中判断变量的类型
2020/07/29 Python
HTML5 图片悬停放大的实现代码示例
2019/12/04 HTML / CSS
俄罗斯运动鞋商店:Sneakerhead
2018/05/10 全球购物
施华洛世奇匈牙利官网:SWAROVSKI匈牙利
2019/07/06 全球购物
澳大利亚电商Catch新西兰站:Catch.co.nz
2020/05/30 全球购物
销售代表求职自荐信
2013/10/01 职场文书
酒店中秋节促销方案
2014/01/30 职场文书
2015年个人现实表现材料
2014/12/10 职场文书
《孙子兵法》:欲成大事者,需读懂这些致胜策略
2019/08/23 职场文书
创业计划书之健康营养产业
2019/10/15 职场文书