业务需要封装递归组件
注意点
- 需要递归的组件必须有
name属性
- 自调用时必须有出口(不满足条件时停止调用),否则内存溢出。
- 在父组件修改或重组传入的数据时,父组件调用
$set更新引用类型数据。
- 在递归组件中修改父组件传入的数据需要通过
computed做双向绑定。如果视图不更新,调用$forceUpdate()。
- 自调用时也需要给自己绑定自定义方法(就像在父组件使用子组件时的绑定。):值得一提的是:不可以直接绑定子组件的方法,否则点击递归的内层时会多次触发该事件,需要改写为
@你的自定义事件="(参数)=>$emit(你的自定义事件,参数)的形式。
核心代码:简易版
//子组件
<style lang="less" scoped>
.my-tree {
.tree-wrapper {
padding-left: 20px;
}
.tree-item {
height: 30px;
line-height: 30px;
overflow: hidden;
cursor: pointer;
transition: all .1s ease;
.tree-item-children {}
.on {
display: block;
}
.off {
display: none;
}
}
.expand {
height: auto;
}
.selected {
background: rgb(216, 224, 238);
font-weight: bold;
color: #000;
}
.loading {
text-align: center;
}
}
</style>
<template>
<div class="my-tree">
<div v-if="data?.length" class="tree-wrapper">
<div @click.stop="onCurrentNode($event, { item, data, index })" v-for="(item, index) in data" :key="index"
:class="['tree-item', item.expand && 'expand']">
<template v-if="item.children?.length && !customHeader">
<Icon :type="item.expand ? 'ios-arrow-down' : 'ios-arrow-forward'" />
</template>
<span v-if="!customHeader" :class="[item.selected && 'selected']"> {{ item.title }}</span>
<slot name="header" :index="index" :item="item" />
<WyxTree :class="['tree-item-children', item.expand ? 'on' : 'off']" v-if="item.children?.length"
:data.sync="item.children" :expandOne="expandOne"
@on-current-node="(e, v) => $emit('on-current-node', e, v)"/>
</div>
</div>
<div v-else class="loading">{{ emptyText }}</div>
</div>
</template>
<script>
export default {
name: 'MyTree',
data() {
return {
}
},
props: {
data: {
type: Array,
default: []
},
customHeader: {
type: Boolean,
default: false
},
expandOne: {
type: Boolean,
default: false
},
emptyText: {
type: String,
default: '加载中 ... '
}
},
computed: {
data: {
get() {
return this.$props.data
},
set(v) {
this.$emit('update:data', v)
}
}
},
methods: {
handleExpand(nodeList, node) {
node.expand = !node.expand
node.selected = !node.selected
if (this.expandOne) {
nodeList = nodeList.map(item => {
if (item.title !== node.title) {
item.expand = false
item.selected = false
}
return item
})
}
},
onCurrentNode(e, v) {
const { item, data } = v
this.handleExpand(data, item)
this.$forceUpdate()
this.$emit('on-current-node', e, v)
}
},
}
</script>