vue自定义树组件s-tree

本组件是基于Vue2的自定义tree组件,参考了weibangtuo的实现,实现了以下功能:

  • 节点单击钩子函数与选中效果
  • 树节点默认的增删改

使用

代码

1.基础使用:给s-tree组件传递tree-data即可,treeData中单个节点的数据结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
name: 'Node Name',
title: 'Node Tag title attr',
isParent: true, // Requested for parent node
isOpen: false, // Control node to fold or unfold
icon: 'fa fa-folder', // Icon class name
openedIcon: 'fa fa-folder-open', // 节点打开时的icon样式
closedIcon: 'fa fa-folder', // 节点折叠时的icon样式
children: [],
buttons: [
{
title: 'icon button tag title attr', //[opt]
icon: 'fa fa-edit',
click: function (node) {
// 自定义事件
}
}
],
}

本例所使用的json数据
2.节点单击事件:监听node-click,此方法接受了node参数(点击的节点对象)
3.节点后的按钮事件: buttonsclick的值可以是自定义方法,也可以默认方法,默认有addNodedelNodeeditNode字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<template>
<div class="tree-demo">
<s-tree :tree-data = "treeData" @node-click="nodeClick"></s-tree>
</div>
</template>
<script>
import sTree from "src/common/component/tree";
let treeData = require("./tree.json");
//自定义事件
treeData[0].children[1].buttons[0].click=function(node){
alert('自定义添加事件');
}
export default {
data(){
return {
treeData: treeData
}
},
components:{
sTree
},
methods:{
nodeClick(node){
console.log(node);
}
}
}
</script>

效果图

s-tree

组件原理

下面是一部分需要注意的地方讲解,其他的请查看底部的源代码链接

使用递归组件

因为不确定树有多少层,所以必须得使用递归组件,递归组件最重要的是什么时候跳出递归,本例使用了如下条件:
tree.vue

1
2
3
4
5
6
7
8
<template>
<ul class="s-tree">
<s-tree-item v-for="node in innerTreeData" :key="node.name"
:node="node">
<s-tree v-if="node.isOpen && node.children" :tree-data="node.children"></s-tree>
</s-tree-item>
</ul>
</template>

node-click事件实现

由于组件是递归的,无法直接$emit事件给外部钩子函数,所以循环获取到了最外层的s-treevue实例,通过此实例$emit事件暴漏给外部钩子函数
tree-item.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export default {
methods:{
nodeClick(){
let _this = this;
while(isNotTree(_this.$parent)){
_this = _this.$parent;
}
_this.$emit('node-click',this.node);
}
}
}
function isNotTree(vm){
let classStr = vm.$el.className;
if(classStr.indexOf('s-tree')!==-1){
return true;
}
return false;
}

单击节点选中效果实现

s-tree-item如果是单个循环的组件,不是递归的,那么直接在外层的s-tree创建变量储存选中的值,在s-tree-item内部与该值判断来实现选中效果就可以了,但是递归组件中s-tree也可能生成了多个,所以这个值不能储存在s-tree里,只能储存在一个单例里,这儿我使用了事件中心,代码如下:
tree-item.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<template>
<li class="s-tree-item" @click.stop="nodeClick">
<i :class="[statusIconClass]"></i>
<a :class="{'is-active': activeValue === node.name}">
<i :class="[node.icon,nodeIconClass]"></i>
{{node.name}}
<i v-if="node.buttons" v-for="button in node.buttons" class="iButton"
:class="[button.icon]"
:title="button.title"></i>
</a>
<slot></slot>
</li>
</template>
<script>
import Bus from './bus.vue';
export default {
computed:{
activeValue(){
return Bus.activeValue;
}
},
methods:{
nodeClick(){
Bus.$emit('active',this.node.name);
}
}
}
</script>

bus.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script>
import Vue from 'vue';
export default new Vue({
name: 'bus',
data(){
return {
activeValue: ''
}
},
created(){
this.$on('active',this.active);
},
methods:{
active(value){
this.activeValue = value;
}
}
});
</script>

对了,这儿使用vuex也是可以的。

结语

堂 wechat
欢迎关注我的微信公众号,里面有各种小故事哦!
坚持原创技术分享,您的支持将鼓励我继续创作!