vue3 递归组件

273 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情

递归组件在我们日常使用的过程当中,这个用法虽然说不会经常是使用,但是我们还是需要知道他的使用方法,比如让我们自己写一个侧边菜单栏,可能会包括n多级,再比如我们下面这种表单,组件递归只能用在有子属性的数据,下面我们就介绍其中一种的用法。

我们可以看下我们要循环递归的数据

export const comdata = [
    {
        id: 1,
        name: '小明',
        age: 44,
        children: [
            {
                id: 2,
                name: '小李',
                age: 43,
            },
            {
                id: 3, 
                name: 'Rose',
                age: 22,
                children: [
                    {
                        id: 4,
                        name: '小张',
                        age: 44
                    },
                    {
                        id: 5,
                        name: 'JJJ',
                        age: 4
                    }
                ],
            }
        ],
    },
    {
        id: 6,
        name: 'sam',
        age: 9,
        children: [
            {
                id: 7,
                name: 'jjj',
                age: 44,
                children: [
                    {
                        id: 8,
                        name: "张三",
                        age: 1,
                    }
                ],
            }
        ]
    },
]

上面是我们要用到的递归数据,我们在使用之前需要把他转化为响应式数据需要用到vue3的 reactive 代码我只写重要的部分,其他的地方就不行,思路会写在代码上

 <customerZ :data="state.data" @setAge="setAge"></customerZ> // 和vue2一样的传递数据 接收子组件数据的方式和vue2也是一样的     
 import { reactive } from 'vue' // 引用reactive 将对象转化为响应式
  setup() {
    function setAge(id,age) { // 接收子组件方法
      console.log(id,age)
    }
   const state = reactive({ // 用法 就不过多赘述了,我之前的文章也介绍过
        data: comdata
     }) 
     return {
     state,
     setAge
     } 
     }

下面就是子组件的写法,递归组件的写法还有有一些不同的

// 写这个递归组件,最重要的不是把ui渲染出来,最重视添加事件,并且每个input框的事件 相互不影响才是最重要的
  <li v-for="(item,index) in props.data" :key="index">
    <p>id: {{item.id}}</p>
    <p>名字: {{item.name}}</p>
    <p>
        <span>{{item.age}}</span>
        <span> 
            <input type="text" :value="item.age" @input="setAge(item.id,$event.target.value)"> 
           // 上面我们给input框添加了input时间了,我们要保证每个input都是独立,我们就需要知道这个item的id了 
        </span>
    </p>   
    // 上面的写法还是比较正常的
    // 主要是下面的写法可能会造成一些困扰,为啥会这样写,组件的名字默认会使用文件的名称的这是vue3的特性,其实下面的写法就是在循环整个组件
    <ul v-if="item.children">
        <customerZ :data="item.children"></customerZ>   
    </ul>
  </li>
// 写的并不正规,只要是描述思路 下面对父级数据的接收  
export default {
    props: ['data'],
  setup(props,ctx) {
    function setAge(id,age) {
     ctx.emit("setAge",{ id,age }) // 添加emit事件
    }
    return {
       props
    }
  }
}
// 接收参数的第两种写法 这个方法比较简洁,用那种方法看我们自己
<script setup>
   let props = defineProps({
     data: Array,
   }) 
   let emit =  defineEmits([setAge])
   function setAge(id,age) { // 这是我们第两种父子组件写法的方式
      emit("setAge",id,age)
   }
</script>

下面可以看下写好的动画,主要看打印数据

2022-10-20 224731.gif

我们已经可以知道了,我们input事件是谁触发的了,说明我们的写法没有问题,