vue组件进阶-递归组件

前言

递归组件,顾名思义就是递归来使用组件(废话)。

递归都会吧,组件也会吧。好了,你已经学会递归组件了(✿◕‿◕✿)

开个玩笑,开始学习递归组件吧

递归组件的使用场景

递归组件的使用场景包括但不限于以下两种情况:

  1. 用于显示树状结构界面:递归组件能够自我调用,每次调用时传入不同的变量,这使得它非常适合用于显示树状结构界面,比如文件目录、组织结构等。
  2. 解决迷宫问题:递归是一种有效的解决迷宫问题的算法,它能够通过回溯的方式找出迷宫的所有路径。

总的来说就是当数据层级比较多,且不固定时,那么我们就可以使用递归组件来对需求的实现

递归组件的实现

一般情况下我们所见能遇见的递归组件写法就是结构树

1、首先我们先定义一个List组件

2、然后让它调用他自己

3、这样它就会一直调下去

4、然后就栈溢出了

当然这不是我们想要的,跟递归函数一样,我们需要有一个临界值来控制一下 如下:

vue 复制代码
 List.vue
    
<template>
  <div>
    <ul>
      <template v-for="(item, index) in lsit" :key="item.id ? item.id : index">
        <li>{{ item.name }}</li>
        //递归的肯定还是还是一个数组  所以我们要先判断item上是否有这个属性 
        //如果有且length不等于0的情况下才会继续渲染下去
         <List
          v-if="item.children?.length"
          :lsit="item.children" />
      </template>
    </ul>
  </div>
</template>

//需要接收一下参数
export default {
  props:['list']
 }

这样我们最基本的递归组件就实现了,来调用一下这个组件,并传入参数试试

vue 复制代码
Home.vue
<template>
  <div>
    <List :lsit="list"/>
  </div>
</template>
//传入递归组建的参数
const lsits = [
  {
    name: "22",
    id: 1,
    children: [
      {
        name: "33",
        id: 11,
        children: [
          {
            name: "44",
            id: 111,
            children: [
              { name: "55", id: 1111 },
              { name: "56", id: 1112 },
            ],
          },
          { name: "44", id: 111, children: [] },
        ],
      },
      { name: "34", id: 12, children: [{ name: "45", id: 112 }] },
    ],
  },
];

效果: 这么看来,这个递归组件算是基本成功了,但是我们不单单只展现就好了,这么多数据,不会一次性就展示完。现在的需求就是当我们点击父节点,才会显示子节点

这里,我们只需要加上判定来动态修改它的class即可,flag一定要是个数组,否则节点之间展开会相互影响,当flag为空数组时,它所绑定的布尔值全为false

vue 复制代码
List.vue
 <ul ref="idd">
      <template v-for="(item, index) in lsit" :key="item.id ? item.id : index">
        <li @click.stop="nodeClick(item, index)">{{ item.name }}</li>
        <List
          v-if="item.children?.length"
          :lsit="item.children"
          :class="flag[index] ? 'show' : 'hide'" />
      </template>
    </ul>
    
 
export default {
  props:['list'],
  data() {
    return {
      flag: [],
    };
  },
  methods: {
    nodeClick(v, i) {
      flag[i] = !flag[i];
    },
  },
};

这样就可以点击节点来控制子节点的显示隐藏了

不仅要展示树节点,还要知道我们点击了哪个节点,并将这个节点的数据返回出来,我们可以这样写: 1、定义一个存储节点的变量

2、当点击了这个节点就将点击当前节点的数据赋值给这个变量

3、监听这个变量,如果改变了,那么就会emit出去

4、递归组件,组件内引入了自己,当emit出来之后就会触发node-click事件,触发之后会将值赋值给存储节点的变量,此时那个变量又改变了,会再次emit,直到调出这个递归组件

5、这个时候调用递归组件的父组件就拿到了你点击的那个节点的数据

vue 复制代码
List.vue
    <ul>
      <template v-for="(item, index) in lsit" :key="item.id ? item.id : index">
        <li @click.stop="nodeClick(item, index)">{{ item.name }}</li>
        <List
          v-if="item.children?.length"
          :lsit="item.children"
          :class="flag[index] ? 'show' : 'hide'"
          @node-click="node" />
      </template>
    </ul>
    
   js
 export default {
  props: ["list"],
  data() {
    return {
      flag: [],
      val: "",
    };
  },
  watch: {
  //这里深度监听一下,只要改变就emit
    val: {
      deep: true,
      handler(v) {
        this.$emit("nodeClick", v);
      },
    },
  },
  methods: {
    nodeClick(v, i) {
      flag[i] = !flag[i];
      this.val = v;
    },
    node(v) {
      this.val = v;
    },
  },
};

这样我们最基本树状结构组件就实现了:

vue3中基本代码实现

vue 复制代码
 List.vue
<template>
  <div>
    <ul>
      <template v-for="(item, index) in lsit" :key="item.id ? item.id : index">
        <li @click.stop="nodeClick(item, index)">{{ item.name }}</li>
        <List
          v-if="item.children?.length"
          :lsit="item.children"
          :class="flag[index] ? 'show' : 'hide'"
          @node-click="node" />
      </template>
    </ul>
  </div>
</template>

<script setup>
import { ref, watchEffect } from "vue";
import List from "./List.vue";
const props = defineProps({
  lsit: {
    type: Array,
  },
});
const emit = defineEmits(["nodeClick"]);
const flag = ref([]);
const shu = ref();
const nodeClick = (v, i) => {
  flag.value[i] = !flag.value[i];
  shu.value = v;
};
const node = (v) => {
  shu.value = v;
};
watchEffect(() => {
  if (shu.value) {
    emit("nodeClick", shu.value);
  }
});
</script>

结尾

递归组件还是很好理解的,原理类似于递归函数,只要处理好了临界值的判定,以及返回值的处理,其他基本上都没有什么。

另外我知道自己的文笔不好,欢迎批评和提出宝贵的建议!

相关推荐
bubusa~>_<19 分钟前
解决npm install 出现error,比如:ERR_SSL_CIPHER_OPERATION_FAILED
前端·npm·node.js
yanglamei196233 分钟前
基于Python+Django+Vue的旅游景区推荐系统系统设计与实现源代码+数据库+使用说明
vue.js·python·django
流烟默1 小时前
vue和微信小程序处理markdown格式数据
前端·vue.js·微信小程序
梨落秋溪、1 小时前
输入框元素覆盖冲突
java·服务器·前端
菲力蒲LY2 小时前
vue 手写分页
前端·javascript·vue.js
天下皆白_唯我独黑2 小时前
npm 安装扩展遇到证书失效解决方案
前端·npm·node.js
~欸嘿2 小时前
Could not download npm for node v14.21.3(nvm无法下载节点v14.21.3的npm)
前端·npm·node.js
化作繁星3 小时前
React 高阶组件的优缺点
前端·javascript·react.js
zpjing~.~3 小时前
vue 父组件和子组件中v-model和props的使用和区别
前端·javascript·vue.js
做一颗卷心菜3 小时前
Promise
开发语言·前端·javascript