公司需求是需要在手机端展示 tree 层级的分类下拉列表。因为没有思路所以在网上查询组件递归的方法。最终结合搜索到了一种组件递归调用方法。 记录时间 20210312
效果如下图:
html代码块:
1、在执行这一块的时候 因为需要点击触发emit事件,所以执行了selectClassify,
2、但是因为子组件递归执行的时候 和当前组件执行的一样的方法但是 emit方法没有通过组件暴露出来
3、所以<classify-tree :treeData="item.children" @select="emitItem" ></classify-tree>
在这个子组件递归中需要执行@select=“emitItem” 将组件的select方法暴露给最外层,不写这个在最外层只能接收到第一层的select方法哦
4、这边有一个item.level
属性是记录当前循环的层级的,这个数据必须在最外层传入数据时候传入哦,因为写在组件内部的话是每一次递归都会重新刷新的,所以层级是没有办法保留的
<view class="classifyTree">
<view class="tree" v-for="(item, index) in classData" :key="index">
<view class="classify border-bottom"
:class="[{
'active': item.openChild
}]"
:style="item.level>3? 'padding-left: 9px' : 'padding-left:'+(item.level*3)+'px' "
@click="selectClassify(item)">
<!-- 可以 在上面自己定义子集的缩进 -->
<!-- 没有子节点不渲染箭头 这边使用了openChild 控制了箭头的向上展开和向下收缩-->
<uni-icons v-if="item.children && item.children.length > 0"
:type="item.openChild? 'arrowup' : 'arrowdown'" size="15" color="#ccc">
</uni-icons>
<view class="text">
{{item.title}}
</view>
</view>
<view v-if="item.openChild">
<!-- 这边是作为一个递归的出口 -->
<view class="child" v-if="item.children && item.children.length > 0">
<classify-tree :treeData="item.children" @select="emitItem" ></classify-tree>
</view>
</view>
</view>
</view>
JavaScript 代码块
// 在这里引用自己代码进行调用自己(核心代码)
import classifyTree from './classifyTree'
export default {
name: 'classifyTree'
props: {
treeData: Array,
},
data() {
return {
classData: [],
}
},
created() {
// 通过赋值data数据中的classData 变量 可以让数据变成响应式对象
this.classData = this.treeData;
},
components: {
classifyTree
},
methods: {
// $emit
emitItem(item) {
this.$emit('select', item);
},
// 选中后 触发emit事件 并且 执行openChild 属性改变展开下一层级
selectClassify(item) {
// 必须通过$set将openChild 属性转变成响应式属性
this.$set(item, 'openChild', !item['openChild']);
this.emitItem(item)
}
}
}
css 代码
<style lang="scss">
.classifyTree {
.tree {
.classify {
display: flex;
align-items: center;
justify-content: space-between;
padding: 40rpx 0;
.text {
color: #1F315F;
font-size: 10px;
}
&.active {
.text {
// 选中的颜色表现 目前是多选的
color: #13C2C2;
}
}
}
}
}
</style>
最终代码
<template>
<view class="classifyTree">
<view class="tree" v-for="(item, index) in classData" :key="index">
<view class="classify border-bottom"
:class="[{
'active': item.openChild
}]"
:style="item.level>3? 'padding-left: 9px' : 'padding-left:'+(item.level*3)+'px' "
@click="selectClassify(item)">
<view class="text">
{{item.title}}
</view>
<!-- 没有子节点不渲染箭头 -->
<!-- <uni-icons v-if="item.children && item.children.length > 0"
:type="item.openChild? 'arrowup' : 'arrowdown'" size="15" color="#ccc"></uni-icons> -->
</view>
<view v-if="item.openChild">
<view class="child" v-if="item.children && item.children.length > 0">
<classify-tree :treeData="item.children" @select="emitItem" ></classify-tree>
</view>
</view>
</view>
</view>
</template>
<script>
import classifyTree from './classifyTree'
export default {
props: {
treeData: Array,
},
data() {
return {
classData: [],
}
},
created() {
this.classData = this.treeData;
},
components: {
classifyTree
},
methods: {
// 打开树
emitItem(item) {
this.$emit('select', item);
},
selectClassify(item) {
this.$set(item, 'openChild', !item['openChild']);
this.emitItem(item)
}
}
}
</script>
<style lang="scss">
.classifyTree {
.tree {
.classify {
display: flex;
align-items: center;
justify-content: space-between;
padding: 40rpx 0;
.text {
color: #1F315F;
font-size: 10px;
}
&.active {
.text {
color: #13C2C2;
}
}
}
}
}
</style>
后续实现了单多选的功能 有需要可以联系我