先看效果
任意树形数据均可直接展示
主要代码片段
注意:最好是去看示例的完整实现,这个非常重要,下面只是稍微提了下主要方法和思路。
思路:使用栈来深度优先遍历,将除根节点外所有节点都找到它的父节点,并添加到节点上。为后续选中子节点判断和修改父节点状态做准备。
树形结构结构如下:
[
{
"title": "水果",
"children": [
{
"title": "香蕉",
"children": [
{
"title": "香蕉A",
"children": [
{
"title": "香蕉AA"
},
{
"title": "香蕉BB"
}
]
},
{
"title": "香蕉B"
}
]
},
{
"title": "苹果"
},
{
"title": "梨"
},
{
"title": "草莓"
}
]
},
{
"title": "蔬菜",
"children": [
{
"title": "芹菜"
},
{
"title": "菠菜"
},
{
"title": "土豆"
},
{
"title": "白菜"
}
]
}
]
添加父节点方法
transform() {
console.log("transform")
let stack = [...this.list]
let childCount = 0
let parent = null
while (stack.length) {
let top = stack.pop()
// console.log(top)
if (top.children) {
if (childCount) {
stack.push(top)
let length = stack.length
while (childCount) {
stack[length - 1].parent = parent
childCount--
length--
}
stack.pop()
}
childCount = top.children.length
parent = top
stack.push(... top.children)
} else {
if (childCount) {
top.parent = parent
childCount--
}
}
}
console.log(this.list)
}
组件递归
app.component('boxs', {
name: "boxs",
data() {
return {isShow: false}
},
props: [
"child", 'list'
],
methods: {
check(child) { // console.log(this)
console.log("check")
this.$emit('my-parent', child)
},
getAllchildren(child) {
if (!child.children)
return []
let all = []
let stack = [...child.children]
while (stack.length) {
let top = stack.pop()
all.push(top)
if (top.children) {
stack.push(... top.children)
}
}
return all
},
judgeParent(child) { // parent
let parent = child // 选中节点也要判断父亲情况
while (parent) {
let all = this.getAllchildren(parent) // 获取所有孩子
let checkes = all.filter(item => item.checked) // 判断孩子的勾选状态
if (checkes.length === 0) { // 如果孩子的勾选成功个数为0,则置空父亲状态
parent.status = null
} else { // 如果孩子的勾选成功个数不为0
if (checkes.length === all.length) { // 如果孩子的勾选成功个数为所有孩子个数,父亲勾选状态置为成功,且置父亲状态位空
parent.checked = true
parent.status = null
} else { // 如果孩子的勾选成功个数不为所有孩子个数,父亲勾选状态置为失败,且置父亲状态为半成功
parent.checked = false
parent.status = "half"
}
} parent = parent.parent // 更新父亲
}
},
oks(child) {
console.log("boxs")
console.log(child)
// 判断选中节点有没有child
if (child.children) { // 如果有孩子
let checked = !child.checked
// 本身勾选取反
// 下面是遍历所有孩子
let stack = [child]
while (stack.length) {
let top = stack.pop()
top.checked = checked // 孩子勾选取反
if (top.children) {
stack.push(... top.children)
}
}
// 判断父亲
this.judgeParent(child)
} else { // 如果没有孩子
child.checked = !child.checked // 本身勾选取反
this.judgeParent(child) // 判断父亲
}
}
},
template: `
<div>
<i style="cursor: pointer;user-select: none;" v-if="child.children" @click="isShow=!isShow">*</i><i v-else style="visibility: hidden;">*</i>
<span>
<!-- <i v-if="child.status === 'half'">half</i> -->
<input :class="{'half': child.status === 'half'}" @click="check(child)" :checked="child.checked" type="checkbox" :id="child.title">
<label :for="child.title">{{child.title}}</label>
</span>
<div v-show="isShow" style="padding-left: 20px;" v-if="child.children">
<boxs :list="list" v-for="item in child.children" :child="item" @my-parent="oks"></boxs>
</div>
</div>
`
})
判断孩子和父亲是否被选中
在示例代码中
完整示例
https://github.com/liulinboyi/tree