You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
4.4 KiB

6 years ago
<template>
<div class="org-tree-container">
<div class="org-tree" :class="{horizontal, collapsable}">
6 years ago
<org-tree-node
:data="dataCloned"
:props="props"
:horizontal="horizontal"
:label-width="labelWidth"
:collapsable="collapsable"
:label-class-name="labelClassName"
:node-render="nodeRender"
:button-render="buttonRender"
@on-expand="handleExpand"
@on-node-click="handleNodeClick"
6 years ago
/>
</div>
</div>
</template>
<script>
import OrgTreeNode from "./OrgTreeNode"
6 years ago
export default {
name: 'OrgTree',
components: {OrgTreeNode},
props: {
data: {required: true},
6 years ago
props: {
type: Object,
default: () => ({
id: 'id',
label: 'label',
expand: 'expand',
children: 'children'
})
6 years ago
},
horizontal: Boolean,
collapsable: Boolean,
nodeRender: Function,
buttonRender: Function,
labelWidth: [String, Number],
labelClassName: [Function, String],
expandAll: Boolean
},
data() {
return {
flatData: {},
dataCloned: {}
}
},
watch: {
data(newData) {
this._cloneData(newData)
this._mapData(this.dataCloned, item => {
const {expand} = this.flatData[item[this.props.id]] || {}
if (expand) this.$set(item, this.props.expand, true)
})
this._toggleExpand(this.dataCloned, this.expandAll)
6 years ago
},
expandAll(status) {
this._toggleExpand(this.dataCloned, status)
}
},
methods: {
_cloneData(newData) {
this.dataCloned = JSON.parse(JSON.stringify(newData))
6 years ago
},
_setFlatData(data) {
this.flatData[data[this.props.id]] = data
},
/**
* @description 工具方法用于遍历树状数据的每个节点 fn为在该节点做的操作其有一个参数即当前节点数据
*/
_mapData(data, fn) {
fn(data)
const children = data[this.props.children]
children && children.forEach(child => this._mapData(child, fn))
},
/**
* @description 用来便利所有节点数据将树状数据扁平化存放到flatData用于数据更新后展开状态的恢复
*/
_updateExpandStatus() {
this._mapData(this.dataCloned, this._setFlatData)
},
_toggleExpand(data, status) {
if (Array.isArray(data)) {
data.forEach(item => {
this.$set(item, this.props.expand, status)
const children = item[this.props.children]
if (children) {
this._toggleExpand(children, status)
6 years ago
}
})
}
else {
this.$set(data, this.props.expand, status)
const children = data[this.props.children]
if (children) {
this._toggleExpand(children, status)
6 years ago
}
}
},
collapse(list) {
list.forEach(child => {
if (child[this.props.expand]) {
child[this.props.expand] = false
6 years ago
}
const children = child[this.props.children]
children && this.collapse(children)
})
},
handleExpand(data) {
if (this.props.expand in data) {
data[this.props.expand] = !data[this.props.expand]
const children = data[this.props.children]
if (!data[this.props.expand] && children) {
this.collapse(children)
6 years ago
}
}
else this.$set(data, this.props.expand, true)
this.$emit('on-expand', data, data[this.props.expand])
6 years ago
this._updateExpandStatus()
},
handleNodeClick(e, data) {
this.$emit('on-node-click', e, data, () => this.handleExpand(data))
6 years ago
}
},
mounted() {
this._cloneData(this.data)
this._updateExpandStatus()
this._toggleExpand(this.dataCloned, this.expandAll)
6 years ago
}
}
6 years ago
</script>
6 years ago
<style lang="scss" src="./tree.scss"></style>