uniapp/vue 组件递归

公司需求是需要在手机端展示 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>

后续实现了单多选的功能 有需要可以联系我

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值