perf[Tree-Table]: refactor tree-table
This commit is contained in:
parent
5508f05132
commit
f8f7667ab1
|
@ -1,29 +1,48 @@
|
||||||
/**
|
|
||||||
* @Author: jianglei
|
|
||||||
* @Date: 2017-10-12 12:06:49
|
|
||||||
*/
|
|
||||||
'use strict'
|
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
export default function treeToArray(data, expandAll, parent = null, level = null) {
|
|
||||||
|
// Flattened array
|
||||||
|
export default function treeToArray(data, children = 'children') {
|
||||||
let tmp = []
|
let tmp = []
|
||||||
Array.from(data).forEach(function(record) {
|
data.forEach((item, index) => {
|
||||||
if (record._expanded === undefined) {
|
Vue.set(item, '_index', index)
|
||||||
Vue.set(record, '_expanded', expandAll)
|
tmp.push(item)
|
||||||
}
|
if (item[children] && item[children].length > 0) {
|
||||||
let _level = 1
|
const res = treeToArray(item[children], children)
|
||||||
if (level !== undefined && level !== null) {
|
tmp = tmp.concat(res)
|
||||||
_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
|
return tmp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function addAttrs(data, { parent = null, preIndex = false, level = 0, expand = false, children = 'children', show = true, select = false } = {}) {
|
||||||
|
data.forEach((item, index) => {
|
||||||
|
const _id = (preIndex ? `${preIndex}-${index}` : index) + ''
|
||||||
|
Vue.set(item, '_id', _id)
|
||||||
|
Vue.set(item, '_level', level)
|
||||||
|
Vue.set(item, '_expand', expand)
|
||||||
|
Vue.set(item, '_parent', parent)
|
||||||
|
Vue.set(item, '_show', show)
|
||||||
|
Vue.set(item, '_select', select)
|
||||||
|
if (item[children] && item[children].length > 0) {
|
||||||
|
addAttrs(item[children], {
|
||||||
|
parent: item,
|
||||||
|
level: level + 1,
|
||||||
|
expand,
|
||||||
|
preIndex: _id,
|
||||||
|
children,
|
||||||
|
status,
|
||||||
|
select
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cleanParentAttr(data, children = 'children') {
|
||||||
|
data.forEach(item => {
|
||||||
|
item._parent = null
|
||||||
|
if (item[children] && item[children].length > 0) {
|
||||||
|
addAttrs(item[children], children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
|
@ -1,127 +1,183 @@
|
||||||
<template>
|
<template>
|
||||||
<el-table :data="formatData" :row-style="showRow" v-bind="$attrs">
|
<el-table :data="tableData" :row-style="showRow" v-bind="$attrs" v-on="$listeners" >
|
||||||
<el-table-column v-if="columns.length===0" width="150">
|
<slot name="selection" />
|
||||||
|
<slot name="pre-column" />
|
||||||
|
<el-table-column
|
||||||
|
v-for="item in columns"
|
||||||
|
:label="item.label"
|
||||||
|
:key="item.key"
|
||||||
|
:width="item.width"
|
||||||
|
:align="item.align||'center'"
|
||||||
|
:header-align="item.headerAlign">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span v-for="space in scope.row._level" :key="space" class="ms-tree-space"/>
|
<slot :scope="scope" :name="item.key">
|
||||||
<span v-if="iconShow(0,scope.row)" class="tree-ctrl" @click="toggleExpanded(scope.$index)">
|
<template v-if="item.expand">
|
||||||
<i v-if="!scope.row._expanded" class="el-icon-plus"/>
|
<span :style="{'padding-left':+scope.row._level*indent + 'px'} "/>
|
||||||
<i v-else class="el-icon-minus"/>
|
<span v-show="showSperadIcon(scope.row)" class="tree-ctrl" @click="toggleExpanded(scope.$index)">
|
||||||
</span>
|
<i v-if="!scope.row._expand" class="el-icon-plus" />
|
||||||
{{ scope.$index }}
|
<i v-else class="el-icon-minus" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template v-if="item.checkbox">
|
||||||
|
<el-checkbox
|
||||||
|
v-if="scope.row[defaultChildren]&&scope.row[defaultChildren].length>0"
|
||||||
|
:style="{'padding-left':+scope.row._level*indent + 'px'} "
|
||||||
|
:indeterminate="scope.row._select"
|
||||||
|
v-model="scope.row._select"
|
||||||
|
@change="handleCheckAllChange(scope.row)" />
|
||||||
|
<el-checkbox
|
||||||
|
v-else
|
||||||
|
:style="{'padding-left':+scope.row._level*indent + 'px'} "
|
||||||
|
v-model="scope.row._select"
|
||||||
|
@change="handleCheckAllChange(scope.row)" />
|
||||||
|
</template>
|
||||||
|
{{ scope.row[item.key] }}
|
||||||
|
</slot>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column v-for="(column, index) in columns" v-else :key="column.value" :label="column.text" :width="column.width">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<!-- Todo -->
|
|
||||||
<!-- eslint-disable-next-line vue/no-confusing-v-for-v-if -->
|
|
||||||
<span v-for="space in scope.row._level" v-if="index === 0" :key="space" class="ms-tree-space"/>
|
|
||||||
<span v-if="iconShow(index,scope.row)" class="tree-ctrl" @click="toggleExpanded(scope.$index)">
|
|
||||||
<i v-if="!scope.row._expanded" class="el-icon-plus"/>
|
|
||||||
<i v-else class="el-icon-minus"/>
|
|
||||||
</span>
|
|
||||||
{{ scope.row[column.value] }}
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<slot/>
|
|
||||||
</el-table>
|
</el-table>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
/**
|
import treeToArray, { addAttrs } from './eval.js'
|
||||||
Auth: Lei.j1ang
|
|
||||||
Created: 2018/1/19-13:59
|
|
||||||
*/
|
|
||||||
import treeToArray from './eval'
|
|
||||||
export default {
|
export default {
|
||||||
name: 'TreeTable',
|
name: 'TreeTable',
|
||||||
props: {
|
props: {
|
||||||
/* eslint-disable */
|
|
||||||
data: {
|
data: {
|
||||||
type: [Array, Object],
|
type: Array,
|
||||||
required: true
|
required: true,
|
||||||
|
default: () => []
|
||||||
},
|
},
|
||||||
columns: {
|
columns: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
},
|
||||||
evalFunc: Function,
|
defaultExpandAll: {
|
||||||
evalArgs: Array,
|
|
||||||
expandAll: {
|
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
defaultChildren: {
|
||||||
|
type: String,
|
||||||
|
default: 'children'
|
||||||
|
},
|
||||||
|
indent: {
|
||||||
|
type: Number,
|
||||||
|
default: 50
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
guard: 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
// 格式化数据源
|
children() {
|
||||||
formatData: function() {
|
return this.defaultChildren
|
||||||
let tmp
|
},
|
||||||
if (!Array.isArray(this.data)) {
|
tableData() {
|
||||||
tmp = [this.data]
|
const data = this.data
|
||||||
} else {
|
if (this.data.length === 0) {
|
||||||
tmp = this.data
|
return []
|
||||||
}
|
}
|
||||||
|
<<<<<<< HEAD
|
||||||
const func = this.evalFunc || treeToArray
|
const func = this.evalFunc || treeToArray
|
||||||
const args = this.evalArgs ? [].concat([tmp, this.expandAll], this.evalArgs) : [tmp, this.expandAll]
|
const args = this.evalArgs ? [].concat([tmp, this.expandAll], this.evalArgs) : [tmp, this.expandAll]
|
||||||
return func.apply(null, args)
|
return func.apply(null, args)
|
||||||
|
=======
|
||||||
|
addAttrs(data, {
|
||||||
|
expand: this.defaultExpandAll,
|
||||||
|
children: this.defaultChildren
|
||||||
|
})
|
||||||
|
|
||||||
|
const retval = treeToArray(data, this.defaultChildren)
|
||||||
|
return retval
|
||||||
|
>>>>>>> dc6030b... perf[Tree-Table]: refactor tree-table (#1587)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showRow: function(row) {
|
addBrother(row, data) {
|
||||||
const show = (row.row.parent ? (row.row.parent._expanded && row.row.parent._show) : true)
|
if (row._parent) {
|
||||||
row.row._show = show
|
row._parent.children.push(data)
|
||||||
return show ? 'animation:treeTableShow 1s;-webkit-animation:treeTableShow 1s;' : 'display:none;'
|
} else {
|
||||||
|
this.data.push(data)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// 切换下级是否展开
|
addChild(row, data) {
|
||||||
toggleExpanded: function(trIndex) {
|
if (!row.children) {
|
||||||
const record = this.formatData[trIndex]
|
this.$set(row, 'children', [])
|
||||||
record._expanded = !record._expanded
|
}
|
||||||
|
row.children.push(data)
|
||||||
},
|
},
|
||||||
// 图标显示
|
delete(row) {
|
||||||
iconShow(index, record) {
|
const { _index, _parent } = row
|
||||||
return (index === 0 && record.children && record.children.length > 0)
|
if (_parent) {
|
||||||
|
_parent.children.splice(_index, 1)
|
||||||
|
} else {
|
||||||
|
this.data.splice(_index, 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getData() {
|
||||||
|
return this.tableData
|
||||||
|
},
|
||||||
|
showRow: function({ row }) {
|
||||||
|
const parent = row._parent
|
||||||
|
const show = parent ? parent._expand && parent._show : true
|
||||||
|
row._show = show
|
||||||
|
return show
|
||||||
|
? 'animation:treeTableShow 1s;-webkit-animation:treeTableShow 1s;'
|
||||||
|
: 'display:none;'
|
||||||
|
},
|
||||||
|
showSperadIcon(record) {
|
||||||
|
return record[this.children] && record[this.children].length > 0
|
||||||
|
},
|
||||||
|
toggleExpanded(trIndex) {
|
||||||
|
const record = this.tableData[trIndex]
|
||||||
|
const expand = !record._expand
|
||||||
|
record._expand = expand
|
||||||
|
},
|
||||||
|
handleCheckAllChange(row) {
|
||||||
|
this.selcetRecursion(row, row._select, this.defaultChildren)
|
||||||
|
this.isIndeterminate = row._select
|
||||||
|
},
|
||||||
|
selcetRecursion(row, select, children = 'children') {
|
||||||
|
if (select) {
|
||||||
|
this.$set(row, '_expand', true)
|
||||||
|
this.$set(row, '_show', true)
|
||||||
|
}
|
||||||
|
const sub_item = row[children]
|
||||||
|
if (sub_item && sub_item.length > 0) {
|
||||||
|
sub_item.map(child => {
|
||||||
|
child._select = select
|
||||||
|
this.selcetRecursion(child, select, children)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</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>
|
<style>
|
||||||
$color-blue: #2196F3;
|
@keyframes treeTableShow {
|
||||||
$space-width: 18px;
|
from {
|
||||||
.ms-tree-space {
|
opacity: 0;
|
||||||
position: relative;
|
|
||||||
top: 1px;
|
|
||||||
display: inline-block;
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 1;
|
|
||||||
width: $space-width;
|
|
||||||
height: 14px;
|
|
||||||
&::before {
|
|
||||||
content: ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.processContainer{
|
to {
|
||||||
width: 100%;
|
opacity: 1;
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
table td {
|
}
|
||||||
line-height: 26px;
|
@-webkit-keyframes treeTableShow {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.tree-ctrl{
|
.tree-ctrl {
|
||||||
position: relative;
|
position: relative;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: $color-blue;
|
color: #2196f3;
|
||||||
margin-left: -$space-width;
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,89 +1,99 @@
|
||||||
## 写在前面
|
## 写在前面
|
||||||
此组件仅提供一个创建TreeTable的解决思路
|
|
||||||
|
|
||||||
## prop说明
|
此组件仅提供一个创建 TreeTable 的解决思路,本组件充分利用 vue 插槽的特性,方便用户自定义
|
||||||
#### *data*
|
|
||||||
**必填**
|
|
||||||
|
|
||||||
原始数据,要求是一个数组或者对象
|
evel.js 里面 `addAttrs` 方法会给数据添加几个属性,treeTotable 会对数组扁平化。这些操作都不会破坏源数据,只是会新增属性。
|
||||||
```javascript
|
|
||||||
[{
|
调用 addAttrs 后,因\_\_parent 属性,会造成数据循环引用,使用 JSON.stringify()报错,所以转成 JSON 之前需要清除\_\_parent 属性。
|
||||||
key1: value1,
|
|
||||||
key2: value2,
|
## prop 说明
|
||||||
children: [{
|
|
||||||
|
- data(原始数据,要求是一个数组或者对象)
|
||||||
|
- columns(列属性,要求是一个数组)
|
||||||
|
- renderContent(数组扁平化方法(可选))
|
||||||
|
- defaultExpandAll(默认是否全部展开,默认全部展开)
|
||||||
|
- defaultChildren(子元素名,默认为 children)
|
||||||
|
- spreadOffset(扩展符号的偏移量,默认为 50px)
|
||||||
|
- checkboxOffset(复选框的偏移量,默认为 50px)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 代码示例
|
||||||
|
|
||||||
|
- data(**必填**)
|
||||||
|
|
||||||
|
原始数据,
|
||||||
|
|
||||||
|
```js
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
key1: value1,
|
||||||
|
key2: value2,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
key1: value1
|
key1: value1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key1: value1
|
key1: value1
|
||||||
}]
|
}
|
||||||
},
|
]
|
||||||
{
|
},
|
||||||
key1: value1
|
{
|
||||||
}]
|
key1: value1
|
||||||
```
|
}
|
||||||
或者
|
]
|
||||||
```javascript
|
```
|
||||||
{
|
|
||||||
key1: value1,
|
|
||||||
key2: value2,
|
|
||||||
children: [{
|
|
||||||
key1: value1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key1: value1
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### columns
|
或者
|
||||||
列属性,要求是一个数组
|
|
||||||
|
|
||||||
1. text: 显示在表头的文字
|
```javascript
|
||||||
2. value: 对应data的key。treeTable将显示相应的value
|
{
|
||||||
3. width: 每列的宽度,为一个数字(可选)
|
key1: value1,
|
||||||
|
key2: value2,
|
||||||
|
children: [{
|
||||||
|
key1: value1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key1: value1
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
如果你想要每个字段都有自定义的样式或者嵌套其他组件,columns可不提供,直接像在el-table一样写即可,如果没有自定义内容,提供columns将更加的便捷方便
|
- columns
|
||||||
|
|
||||||
如果你有几个字段是需要自定义的,几个不需要,那么可以将不需要自定义的字段放入columns,将需要自定义的内容放入到slot中,详情见后文
|
1. label: 显示在表头的文字
|
||||||
```javascript
|
2. key: 对应 data 的 key。treeTable 将显示相应的 value
|
||||||
[{
|
3. width: 每列的宽度,为一个数字(可选)
|
||||||
value:string,
|
|
||||||
text:string,
|
|
||||||
width:number
|
|
||||||
},{
|
|
||||||
value:string,
|
|
||||||
text:string,
|
|
||||||
width:number
|
|
||||||
}]
|
|
||||||
```
|
|
||||||
|
|
||||||
#### expandAll
|
树表组件将会根据 columns 的 key 属性生成具名插槽,如果你需要对列数据进行自定义,通过插槽即可实现
|
||||||
是否默认全部展开,boolean值,默认为false
|
|
||||||
|
|
||||||
#### evalFunc
|
```javascript
|
||||||
解析函数,function,非必须
|
const columns = [
|
||||||
|
// 建议第一列做展开收缩操作
|
||||||
|
{ label: '', key: '__spread', width: '200' },
|
||||||
|
// 如果添加复选框
|
||||||
|
{ label: '', key: '__checkbox', width: '200' },
|
||||||
|
{
|
||||||
|
label: string,
|
||||||
|
key: string,
|
||||||
|
width: number
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: string,
|
||||||
|
key: string,
|
||||||
|
width: number
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
如果不提供,将使用默认的[evalFunc](./eval.js)
|
#### renderContent
|
||||||
|
|
||||||
如果提供了evalFunc,那么会用提供的evalFunc去解析data,并返回treeTable渲染所需要的值。如何编写一个evalFunc,请参考[*eval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/components/TreeTable/eval.js)或[*customEval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/table/treeTable/customEval.js)
|
解析函数,function,非必须
|
||||||
|
|
||||||
#### evalArgs
|
如果不提供,将使用默认的[evalFunc](./eval.js)
|
||||||
解析函数的参数,是一个数组
|
|
||||||
|
|
||||||
**请注意,自定义的解析函数参数第一个为this.data,第二个参数为, this.expandAll,你不需要在evalArgs填写。一定记住,这两个参数是强制性的,并且位置不可颠倒** *this.data为需要解析的数据,this.expandAll为是否默认展开*
|
如果提供了 evalFunc,那么会用提供的 evalFunc 去解析 data,并返回 treeTable 渲染所需要的值。
|
||||||
|
|
||||||
如你的解析函数需要的参数为`(this.data, this.expandAll,1,2,3,4)`,那么你只需要将`[1,2,3,4]`赋值给`evalArgs`就可以了
|
## 其他
|
||||||
|
|
||||||
如果你的解析函数参数只有`(this.data, this.expandAll)`,那么就可以不用填写evalArgs了
|
如果有其他的需求,请参考[el-table](http://element-cn.eleme.io/#/en-US/component/table)的 api 自行修改 index.vue
|
||||||
|
|
||||||
具体可参考[*customEval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/table/treeTable/customEval.js)的函数参数和[customTreeTable](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/table/treeTable/customTreeTable.vue)的`evalArgs`属性值
|
|
||||||
|
|
||||||
## slot
|
|
||||||
这是一个自定义列的插槽。
|
|
||||||
|
|
||||||
默认情况下,treeTable只有一行行展示数据的功能。但是一般情况下,我们会要给行加上一个操作按钮或者根据当行数据展示不同的样式,这时我们就需要自定义列了。请参考[customTreeTable](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/table/treeTable/customTreeTable.vue),[实例效果](https://panjiachen.github.io/vue-element-admin/#/table/tree-table)
|
|
||||||
|
|
||||||
`slot`和`columns属性`可同时存在,columns里面的数据列会在slot自定义列的左边展示
|
|
||||||
|
|
||||||
## 其他
|
|
||||||
如果有其他的需求,请参考[el-table](http://element-cn.eleme.io/#/en-US/component/table)的api自行修改index.vue
|
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
/**
|
|
||||||
* @Author: jianglei
|
|
||||||
* @Date: 2017-10-12 12:06:49
|
|
||||||
*/
|
|
||||||
'use strict'
|
|
||||||
import Vue from 'vue'
|
|
||||||
export default function treeToArray(data, expandAll, parent, level, item) {
|
|
||||||
const marLTemp = []
|
|
||||||
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)
|
|
||||||
// 如果父元素有偏移量,需要计算在this的偏移量中
|
|
||||||
// 偏移量还与前面同级元素有关,需要加上前面所有元素的长度和
|
|
||||||
if (!marLTemp[_level]) {
|
|
||||||
marLTemp[_level] = 0
|
|
||||||
}
|
|
||||||
Vue.set(record, '_marginLeft', marLTemp[_level] + parent._marginLeft)
|
|
||||||
Vue.set(record, '_width', record[item] / parent[item] * parent._width)
|
|
||||||
// 在本次计算过偏移量后加上自己长度,以供下一个元素使用
|
|
||||||
marLTemp[_level] += record._width
|
|
||||||
} else {
|
|
||||||
// 如果为根
|
|
||||||
// 初始化偏移量存储map
|
|
||||||
marLTemp[record.id] = []
|
|
||||||
// map中是一个数组,存储的是每级的长度和
|
|
||||||
// 初始情况下为0
|
|
||||||
marLTemp[record.id][_level] = 0
|
|
||||||
Vue.set(record, '_marginLeft', 0)
|
|
||||||
Vue.set(record, '_width', 1)
|
|
||||||
}
|
|
||||||
tmp.push(record)
|
|
||||||
if (record.children && record.children.length > 0) {
|
|
||||||
const children = treeToArray(record.children, expandAll, record, _level, item)
|
|
||||||
tmp = tmp.concat(children)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return tmp
|
|
||||||
}
|
|
|
@ -1,137 +1,162 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div>
|
||||||
|
<div class="app-container">
|
||||||
|
<el-tag style="margin-bottom:20px;">
|
||||||
|
<a
|
||||||
|
href="https://github.com/PanJiaChen/vue-element-admin/tree/master/src/components/TreeTable"
|
||||||
|
target="_blank"
|
||||||
|
>Documentation</a>
|
||||||
|
</el-tag>
|
||||||
|
|
||||||
<el-tag style="margin-bottom:20px;">
|
<tree-table
|
||||||
<a href="https://github.com/PanJiaChen/vue-element-admin/tree/master/src/components/TreeTable" target="_blank">Documentation</a>
|
ref="TreeTable"
|
||||||
</el-tag>
|
:data="tableData"
|
||||||
|
:default-expand-all="true"
|
||||||
|
:columns="columns"
|
||||||
|
border
|
||||||
|
default-children="children"
|
||||||
|
@selection-change ="selectChange"
|
||||||
|
>
|
||||||
|
|
||||||
<tree-table :data="data" :eval-func="func" :eval-args="args" :expand-all="expandAll" border>
|
<template slot="selection">
|
||||||
<el-table-column label="事件">
|
<el-table-column type="selection" align="center" width="55"/>
|
||||||
<template slot-scope="scope">
|
|
||||||
<span style="color:sandybrown">{{ scope.row.event }}</span>
|
|
||||||
<el-tag>{{ scope.row.timeLine+'ms' }}</el-tag>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="时间线">
|
<template slot="pre-column">
|
||||||
<template slot-scope="scope">
|
<el-table-column type="expand" width="55">
|
||||||
|
<template>
|
||||||
|
<el-tag type="info">
|
||||||
|
Here is just a placeholder slot, you can display anything.
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template slot="timeline" slot-scope="{scope}">
|
||||||
|
|
||||||
<el-tooltip :content="scope.row.timeLine+'ms'" effect="dark" placement="left">
|
<el-tooltip :content="scope.row.timeLine+'ms'" effect="dark" placement="left">
|
||||||
<div class="processContainer">
|
<div class="processContainer">
|
||||||
<div
|
<div
|
||||||
:style="{ width:scope.row._width * 500+'px',
|
:style="{ width:(scope.row.timeLine||0) * 3+'px',
|
||||||
background:scope.row._width>0.5?'rgba(233,0,0,.5)':'rgba(0,0,233,0.5)',
|
background:scope.row.timeLine>50?'rgba(233,0,0,.5)':'rgba(0,0,233,0.5)',
|
||||||
marginLeft:scope.row._marginLeft * 500+'px' }"
|
marginLeft:scope.row._level * 50+'px' }"
|
||||||
class="process">
|
class="process">
|
||||||
<span style="display:inline-block"/>
|
<span style="display:inline-block"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="操作" width="200">
|
<template slot="append" slot-scope="{scope}">
|
||||||
<template slot-scope="scope">
|
<el-button
|
||||||
<el-button type="text" @click="message(scope.row)">点击</el-button>
|
size="mini"
|
||||||
|
type="primary"
|
||||||
|
@click="addMenuItem(scope.row,'brother')"
|
||||||
|
>Append Brother
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
type="primary"
|
||||||
|
@click="addMenuItem(scope.row,'children')"
|
||||||
|
>Append Child
|
||||||
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
<template slot="operation" slot-scope="{scope}">
|
||||||
</tree-table>
|
<el-button size="mini" type="success" @click="editItem(scope.row)">Edit</el-button>
|
||||||
|
<el-button size="mini" type="danger" @click="deleteItem(scope.row)">Delete</el-button>
|
||||||
|
</template>
|
||||||
|
</tree-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-dialog :visible.sync="dialogFormVisible" title="Edit">
|
||||||
|
<el-form :model="tempItem" label-width="100px" style="width:600px">
|
||||||
|
<el-form-item label="Name">
|
||||||
|
<el-input v-model.trim="tempItem.name" placeholder="Name"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="dialogFormVisible = false">Cancel</el-button>
|
||||||
|
<el-button type="primary" @click="updateItem">Confirm</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
/**
|
|
||||||
Auth: Lei.j1ang
|
import TreeTable from '@/components/TreeTable'
|
||||||
Created: 2018/1/19-14:54
|
import { data } from './data.js'
|
||||||
*/
|
|
||||||
import treeTable from '@/components/TreeTable'
|
|
||||||
import treeToArray from './customEval'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CustomTreeTableDemo',
|
components: { TreeTable },
|
||||||
components: { treeTable },
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
func: treeToArray,
|
tableData: [],
|
||||||
expandAll: false,
|
tempItem: {},
|
||||||
data:
|
dialogFormVisible: false,
|
||||||
|
columns: [
|
||||||
{
|
{
|
||||||
id: 1,
|
label: 'Name',
|
||||||
event: '事件1',
|
key: 'name',
|
||||||
timeLine: 100,
|
expand: true
|
||||||
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: '无'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
args: [null, null, 'timeLine']
|
{
|
||||||
|
label: 'Timeline',
|
||||||
|
key: 'timeline'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Append',
|
||||||
|
key: 'append',
|
||||||
|
width: 300
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Operation',
|
||||||
|
key: 'operation',
|
||||||
|
width: 160
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
created() {
|
||||||
|
this.getData()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
message(row) {
|
getData() {
|
||||||
this.$message.info(row.event)
|
this.tableData = data
|
||||||
|
},
|
||||||
|
editItem(row) {
|
||||||
|
this.tempItem = Object.assign({}, row)
|
||||||
|
this.dialogFormVisible = true
|
||||||
|
},
|
||||||
|
updateItem() {
|
||||||
|
const data = this.$refs.TreeTable.getData()
|
||||||
|
const { _id } = this.tempItem
|
||||||
|
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
if (data[i]._id === _id) {
|
||||||
|
data.splice(i, 1, Object.assign({}, this.tempItem))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dialogFormVisible = false
|
||||||
|
},
|
||||||
|
addMenuItem(row, type) {
|
||||||
|
if (type === 'children') {
|
||||||
|
this.$refs.TreeTable.addChild(row, { name: 'child' })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'brother') {
|
||||||
|
this.$refs.TreeTable.addBrother(row, { name: 'brother' })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deleteItem(row) {
|
||||||
|
this.$refs.TreeTable.delete(row)
|
||||||
|
},
|
||||||
|
selectChange(val) {
|
||||||
|
console.log(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
export const data = [
|
||||||
|
{
|
||||||
|
name: '1',
|
||||||
|
timeLine: 100,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
name: '1-1',
|
||||||
|
timeLine: 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '1-2',
|
||||||
|
timeLine: 60,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
name: '1-2-1',
|
||||||
|
timeLine: 35
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '1-2-2',
|
||||||
|
timeLine: 25
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '2',
|
||||||
|
timeLine: 80,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
name: '2-1',
|
||||||
|
timeLine: 30
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '2-2',
|
||||||
|
timeLine: 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '2-3',
|
||||||
|
timeLine: 60
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '3',
|
||||||
|
timeLine: 40
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
|
@ -1,20 +1,48 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
|
|
||||||
<el-tag style="margin-bottom:20px;">
|
<div style="margin-bottom:20px;">
|
||||||
<a href="https://github.com/PanJiaChen/vue-element-admin/tree/master/src/components/TreeTable" target="_blank">Documentation</a>
|
|
||||||
</el-tag>
|
|
||||||
|
|
||||||
<tree-table :data="data" :columns="columns" border/>
|
<el-button type="primary" class="option-item">
|
||||||
|
<a href="https://github.com/PanJiaChen/vue-element-admin/tree/master/src/components/TreeTable" target="_blank">Documentation</a>
|
||||||
|
</el-button>
|
||||||
|
|
||||||
|
<div class="option-item">
|
||||||
|
<el-tag>Expand All</el-tag>
|
||||||
|
<el-switch
|
||||||
|
v-model="defaultExpandAll"
|
||||||
|
active-color="#13ce66"
|
||||||
|
inactive-color="#ff4949"
|
||||||
|
@change="reset"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="option-item">
|
||||||
|
<el-tag>Show Checkbox</el-tag>
|
||||||
|
<el-switch
|
||||||
|
v-model="showCheckbox"
|
||||||
|
active-color="#13ce66"
|
||||||
|
inactive-color="#ff4949"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<tree-table :key="key" :default-expand-all="defaultExpandAll" :data="data" :columns="columns" border>
|
||||||
|
<template slot="scope" slot-scope="{scope}">
|
||||||
|
<el-tag>level: {{ scope.row._level }}</el-tag>
|
||||||
|
<el-tag>expand: {{ scope.row._expand }}</el-tag>
|
||||||
|
<el-tag>select: {{ scope.row._select }}</el-tag>
|
||||||
|
</template>
|
||||||
|
<template slot="operation" slot-scope="{scope}">
|
||||||
|
<el-button type="primary" size="" @click="click(scope)">Click</el-button>
|
||||||
|
</template>
|
||||||
|
</tree-table>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
/**
|
|
||||||
Auth: Lei.j1ang
|
|
||||||
Created: 2018/1/19-14:54
|
|
||||||
*/
|
|
||||||
import treeTable from '@/components/TreeTable'
|
import treeTable from '@/components/TreeTable'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -22,99 +50,103 @@ export default {
|
||||||
components: { treeTable },
|
components: { treeTable },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
defaultExpandAll: false,
|
||||||
|
showCheckbox: true,
|
||||||
|
key: 1,
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
text: '事件',
|
label: 'Checkbox',
|
||||||
value: 'event',
|
checkbox: true
|
||||||
width: 200
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'ID',
|
label: '',
|
||||||
value: 'id'
|
key: 'id',
|
||||||
|
expand: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: '时间线',
|
label: 'Event',
|
||||||
value: 'timeLine'
|
key: 'event',
|
||||||
|
width: 200,
|
||||||
|
align: 'left'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: '备注',
|
label: 'Scope',
|
||||||
value: 'comment'
|
key: 'scope'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Operation',
|
||||||
|
key: 'operation'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
id: 0,
|
id: 0,
|
||||||
event: '事件1',
|
event: 'Event-0',
|
||||||
timeLine: 50,
|
timeLine: 50
|
||||||
comment: '无'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
event: '事件1',
|
event: 'Event-1',
|
||||||
timeLine: 100,
|
timeLine: 100,
|
||||||
comment: '无',
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
event: '事件2',
|
event: 'Event-2',
|
||||||
timeLine: 10,
|
timeLine: 10
|
||||||
comment: '无'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
event: '事件3',
|
event: 'Event-3',
|
||||||
timeLine: 90,
|
timeLine: 90,
|
||||||
comment: '无',
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
id: 4,
|
id: 4,
|
||||||
event: '事件4',
|
event: 'Event-4',
|
||||||
timeLine: 5,
|
timeLine: 5
|
||||||
comment: '无'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 5,
|
id: 5,
|
||||||
event: '事件5',
|
event: 'Event-5',
|
||||||
timeLine: 10,
|
timeLine: 10
|
||||||
comment: '无'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 6,
|
id: 6,
|
||||||
event: '事件6',
|
event: 'Event-6',
|
||||||
timeLine: 75,
|
timeLine: 75,
|
||||||
comment: '无',
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
id: 7,
|
id: 7,
|
||||||
event: '事件7',
|
event: 'Event-7',
|
||||||
timeLine: 50,
|
timeLine: 50,
|
||||||
comment: '无',
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
id: 71,
|
id: 71,
|
||||||
event: '事件71',
|
event: 'Event-7-1',
|
||||||
timeLine: 25,
|
timeLine: 25
|
||||||
comment: 'xx'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 72,
|
id: 72,
|
||||||
event: '事件72',
|
event: 'Event-7-2',
|
||||||
timeLine: 5,
|
timeLine: 5
|
||||||
comment: 'xx'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 73,
|
id: 73,
|
||||||
event: '事件73',
|
event: 'Event-7-3',
|
||||||
timeLine: 20,
|
timeLine: 20
|
||||||
comment: 'xx'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 8,
|
id: 8,
|
||||||
event: '事件8',
|
event: 'Event-8',
|
||||||
timeLine: 25,
|
timeLine: 25
|
||||||
comment: '无'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -124,6 +156,34 @@ export default {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
showCheckbox(val) {
|
||||||
|
if (val) {
|
||||||
|
this.columns.unshift({
|
||||||
|
label: 'Checkbox',
|
||||||
|
checkbox: true
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.columns.shift()
|
||||||
|
}
|
||||||
|
this.reset()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
reset() {
|
||||||
|
++this.key
|
||||||
|
},
|
||||||
|
click(scope) {
|
||||||
|
console.log(scope)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.option-item{
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue