vue封装树形组件tree
我们项目中有很多需要用到树形组件的,以前写jq的时候用ztree,现在写vue,感觉找不到像ztree一样好用的树形组件,又不想在vue总用jq,所以打算自己封装一个tree组件,花了两个时间才搞完一些基本功能,不过已经可以正常使用了,效果如下:图标的问题大家可以自行用ztree的样式去修改加上上周的折叠式菜单,gitHub网址:https://github.com...
我们项目中有很多需要用到树形组件的,以前写jq的时候用ztree,现在写vue,感觉找不到像ztree一样好用的树形组件,又不想在vue总用jq,所以打算自己封装一个tree组件,花了两个时间才搞完一些基本功能,不过已经可以正常使用了,效果如下:
图标的问题大家可以自行用ztree的样式去修改
加上上周的折叠式菜单,gitHub网址:https://github.com/421119407/vue-kwt-cly
做这个树形菜单是采用了递归组件的思路,因为事件只能传递一层,所以需要每一层子组件触发上一层父组件的事件。
然后通过Vue.set(对象,属性,值)的方式动态给对象添加属性
模板:
<template>
<ul class="ul-ktree">
<li v-for="(item,index) in treeDatas"
:key="item.id"
:class="{leaf:isLeaf(item),'first-node': index === 0 && !isLeaf(item),'only-node': treeDatas.length === 1 && !isLeaf(item)}"
v-show="item.hasOwnProperty('visible') ? item.visible : true">
<div class="ktree-node">
<span @click="expandNode(item)" v-if="!item.parent || item.children && item.children.length>0" :class="item.expanded ? 'tree-open':'tree-close'"></span>
<span v-if="checkModel" :class="[item.checked ? (item.halfCheck ? 'box-halfchecked' : 'box-checked') : 'box-unchecked','inputCheck']">
<input :disabled="item.chkDisabled"
:class="['check', item.chkDisabled ? 'chkDisabled' : '']"
type="checkbox"
@change="changeNodeCheckStatus(item, $event)"
v-model="item.checked"/>
</span>
<span :class="changeStyle()"></span>
<Render :node="item" :template ='tpl'/>
</div>
<transition name="expand" mode="out-in">
<k-tree v-if="!isLeaf(item)"
:datas="item.children"
@node-check='nodeCheck'
@on-click="onClick"
@node-single-check = 'nodeCheck'
:parent="item"
:depth="childDepth+1"
:tpl ="tpl"
v-show="item.expanded"
:checkModel="checkModel"
:halfCheck="halfCheck"
:scoped="scoped"
:iconStyle="iconStyle" >
</k-tree>
</transition>
</li>
</ul>
</template>
父组件传递属性:
props: {
iconStyle: {
type: String,
default: icon.iconStyle.METRO
},
depth: {
type: Number,
default: 1
},
opinions: {
type: Object,
default: () => null
},
datas: {
type: Array,
default: () => []
},
parent: {
type: Object,
default: () => null
},
halfCheck: {
type: Boolean,
default: true
},
multiple: {
type: Boolean,
default: true
},
checkModel: {
type: Boolean,
default: true
},
draggable: {
type: Boolean,
default: false
},
drapAfterExpand: {
type: Boolean,
default: false
},
showCheck: {
type: Boolean,
default: false
},
isAddOrEdit: {
type: Boolean,
default: false
},
scoped: {
type: Boolean,
default: false
},
tpl: Function
}
datas: 父组件向子组件传递数据,也就是我们的树形信息。包括节点id,节点父id。。。
parent: 当前节点的父节点
opinions:封装了节点对应信息,主要用来转换后台传来的数据转成树形菜单适用的数据,我们后台传来的数据一般没有父子关系,需要通过特殊处理,转换成
{
id:1
children:【{
id:11
}】
}
halfCheck:半选模式
checkModel:是否显示复选框
scoped:是否父子关联
multiple:是否可复选
tpl:这返回的是一个函数,可自定义标题模板
在父组件中:
<template>
<div>
<k-tree :datas="treeDatas1" :opinions="opinions" @on-click="onClick"></k-tree>
</div>
</template>
可通过自定义事件绑定on-click,来自定义点击回调事件
数据处理片段:
initDatas() {
let dataArray = []
let pidArray = []
//找出根节点,放入数组中
for (let key of this.datas) {
pidArray.push(key[this.opinions.id]) //遍历数据,把id存储在数据中
}
for (let key of this.datas) {
if (pidArray.indexOf(key[this.opinions.pid]) === -1) { //判断pid是否存在数组中,不存在的那个节点,便是根节点
dataArray.push({
id: key[this.opinions.id],
name: key[this.opinions.name],
checked: key.checked,
visible: key.visible
})
}
}
return this.initArrayDatas(dataArray)
},
initArrayDatas(dataArray) {
for (let key of dataArray) {
let childDatas = []
for (let k of this.datas) { //遍历,通过pid===id建立父子关系
if (key.id === k[this.opinions.pid]) {
childDatas.push({
id: k[this.opinions.id],
name: k[this.opinions.name],
pid: k[this.opinions.pid],
checked: k.checked,
visible: k.visible
})
}
}
key.children = childDatas // 添加进children
if (childDatas.length > 0) {
this.initArrayDatas(childDatas)
}
}
return dataArray
},
筛选节点:
getNodes(opt, data, isOriginal) {
data = data || this.datas
let res = []
for (const node of data) {
for (const [key, value] of Object.entries(opt)) {
if (node[key === value]) {
if (isOriginal) {
res.push(node)
} else {
let n = Object.assign({}, node)
delete n['children']
delete n['parent']
res.push(n)
}
}
}
if (node.children && node.children.length) {
res = res.concat(this.getNodes(opt, node.children, isOriginal))
}
}
return res
},
getSelectNodes(isOriginal) {
return this.getNodes({ select: true }, this.data, isOriginal)
},
getCheckedNodes(isOriginal) {
return this.getNodes({ checked: true }, this.data, isOriginal)
},
opt参数封装筛选条件,如{checked:true,select:true},然后遍历数据找到符合条件的节点并添加到数组中返回
getSelectNodes和getCheckedNodes可用于点击回调中获取选中节点的值
到了这里,我们的属性组件基本就封装完成了,当然了,后期我会逐步完善其他功能。
更多推荐
所有评论(0)