如今,一直在忙着写一个本身独立承担前端部分的项目。公司刚完成的上百个开发工程师开发了一年的大项目,用的技术栈是React。 因为,本身主导的这个项目比较小,项目复杂度比以前的项目差远了。因此,就选了,开发灵活性没 React 高,但开发速度较快的 Vue,同时UI框架用的是 ElementUI。咱们以前用 React 的大项目中,就有不少的地方用到了,穿梭书组件(两个 ElementUI Tree 左树的数据能够穿梭到右面,右树的数据能够穿梭到左面)。好多节点的穿梭书是咱们本身封装的。但这个小项目咱们又用到了穿梭书,然而比较尴尬是,此次用的是 Vue,因此以前用 React 写的组件就只具有程序设计上的参考意义了。同时,我参考了,Element的树的写法的基础上,去是实现了基于Vue的穿梭树。因为,业务比较复杂,这篇文章就先之写 Tree 实现的核心思想吧!前端
固然这个项目中记得引入 ElementUI。 树的每一个节点都要记住本身的当前状态,树闭合展开选中的操做,也经过改变当前节点状态来改变。因此咱们就须要,去把数据进行遍历,生成一个有状态,同时每一个节点有改变的状态的构造树。vue
树的 Datanode
const treeData = [
{
label: "一级 1",
children: [
{
label: "二级 1-1",
}
]
},
{
label: "一级 2",
children: [
{
label: "二级 2-1",
children: [
{
label: "三级 2-1-1"
}
]
}
]
}
]
复制代码
在 Tree.vue 中传入,将 treeData 传入构造函数中TreeStore。 new TreeStore({data: treeData}) 生成了咱们想要的有状态,还能够经过调用内部函数改变自身节点状态的树形数据。element-ui
tree-store.js 代码数组
import Node from './node.js'
export default class TreeStore {
constructor(options) {
for (let option in options) {
if (options.hasOwnProperty(option)) {
this[option] = options[option]
}
}
this.root = new Node({
data: this.data,
store: this
})
}
}
复制代码
node.js 代码bash
import objectAssign from 'element-ui/src/utils/merge';
const getPropertyFromData = function(node, prop) {
const data = node.data || {};
if (typeof prop === 'string') {
return data[prop];
} else {
throw new Error('label data type is not string');
}
};
export default class Node {
constructor(options) {
this.level = 0;
this.childNodes = [];
this.expanded = true; //展开关闭状态
for (let option in options) {
if (options.hasOwnProperty(option)) {
this[option] = options[option]
}
}
this.setData(this.data)
}
get isLeaf() {
return !!this.childNodes.length
}
get label() {
return getPropertyFromData(this, 'label');
}
setExpanded() { // 控制 expanded 来控制页面中树的闭合展开
this.expanded = !this.expanded;
}
setData(data) {
this.data = data;
this.childNodes = []; // 子节点数组
let children;
if (this.level === 0 && this.data instanceof Array) {
children = this.data;
} else {
children = getPropertyFromData(this, 'children') || [];
}
for (let i = 0; i < children.length; i++) {
this.insertChild({ data: children[i] });
}
}
insertChild(child, index, batch) {
if (!child) throw new Error('insertChild error: child is required.');
if (!(child instanceof Node)) {
objectAssign(child, {
parent: this,
store: this.store
});
child = new Node(child);
}
child.level = this.level + 1;
this.childNodes.push(child);
}
}
复制代码
生成新的数据后,咱们就能够在 Tree.vue 中对新数据进行遍历。将构造的数据中的文本渲染到页面中。框架
Tree.vue 中代码函数
<template>
<div class="el-tree" role="tree">
<tree-node
v-for="(child, index) in root.childNodes"
:key="index"
:node="child"
/>
</div>
</template>
<script>
import TreeStore from "./modal/tree-store.js";
import TreeNode from "./TreeNode.vue";
export default {
name: "Tree",
data() {
return {
store: null,
root: null
};
},
props: {
data: {
type: Array
}
},
created() {
this.store = new TreeStore({
data: this.data
})
this.root = this.store.root;
},
components: {
TreeNode
}
};
</script>
复制代码
TreeNode.vue 中代码动画
<template>
<div class="tree">
<div class="el-tree-node__content">
<span
:class="[ {'expanded': node.expanded}, 'el-tree-node__expand-icon' ]"
class="el-icon-caret-right"
@click.stop="handleExpandIconClick"
></span>
<span class="el-tree-node__label">{{node.label}}</span>
</div>
<el-collapse-transition> <!-- 使用了 elementUI 中的动画组件 -->
<div
v-show="node.expanded"
class="el-tree-node__children"
style="padding-left: 18px;"
>
<tree-node
v-for="(item, index) in node.childNodes"
:key="index"
:node="item"
/>
</div>
</el-collapse-transition>
</div>
</template>
<script>
export default {
name: "TreeNode",
props: {
node: Object
},
data() {
return {
data: Array,
isExpande: true
};
},
methods: {
handleExpandIconClick() {
this.node.setExpanded();
}
}
};
</script>
复制代码
好了,这个树是我用 Vue 实现的最最基本的树。抛去了一切业务逻辑,一切只剩最根本,很好理解很简单。固然写成这么简单,有很大一部分缘由也但愿我女友可以看懂。 后面的我会把有业务复杂逻辑的加进来。ui