vue和uni-app的递归组件排坑

有这样一个数组数据,实际可能有很多级。

tree: [
  {
    id: 1,
    name: '1',
    children: [
      { 
        id: 2, 
        name: '1-1', 
        children: [
          {
            id: 7, 
            name: '1-1-1',
            children: []
          }
        ]
      },
      { id: 3, name: '1-2' }
    ]
  },
  {
    id: 4,
    name: '2',
    children: [
      { id: 5, name: '2-1' },
      { id: 6, name: '2-2' }
    ]
  }
]

要渲染为下面这种树形

应该很容易想到使用递归组件,下面就来写一个tree组件。简单用vue2实现一下。

用法很简单

传入tree数据,支持返回当前点击的节点。

实现一下

先写一个tree组件,在components/tree/index.vue

<template>
  <div>
    <div 
      class="node" 
      v-for="node in data" 
      :key="node.id"
    >
      <tree-node 
        :node="node" 
        @node-click="nodeClick"
      >
      </tree-node>
    </div>
  </div>
</template>

<script>
  import treeNode from './tree-node.vue'
  export default {
    components: { treeNode },
    props: {
      data: {
        type: Array,
        default: () => []
      }
    },
    methods: {
      nodeClick(node) {
        this.$emit('node-click', node)
      }
    }
  }
</script>

因为父组件页面中传进来的是个数组,需要先循环这个数组,然后递归渲染每一个子节点,我们就再写一个tree-node组件,专门用来渲染子节点,核心代码递归也是在这个组件中完成的。

同级目录写一个tree-node组件,在components/tree/tree-node.vue

<template>
  <div>
    <!-- 避免冒泡到父组件,要加.stop -->
    <div 
      class="node-name" 
      @click.stop="nodeClick"
    >
      {{node.name}}
    </div>
    <!-- 有children就遍历,递归渲染自身,把每一项传进去 -->
    <div 
      class="children" 
      v-if="node.children && node.children.length"
    >
      <tree-node 
        v-for="item in node.children" 
        :key="item.id" 
        :node="item" 
        v-on="$listeners"
      >
      </tree-node>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'tree-node',
    props: {
      node: Object
    },
    methods: {
      nodeClick() {
        // 因为传入当前组件的是每一级的节点
        // 只需要再传回去就好了
        this.$emit('node-click', this.node)
      }
    }
  }
</script>

<style scoped>
  .node-name {
    cursor: pointer;
  }
  .children {
    padding-left: 20px;
  }
</style>

划重点、抛出问题

  1. 递归的核心是自己调用自己,但要注意边界条件,否则会进入死循环,内存泄漏。对应到以上代码就是v-if="node.children && node.children.length"
  2. 以上代码已经实现了递归渲染,但只是vue2的实现。你可能注意到其中有一个很重要的语句,v-on="$listeners",如果不加会导致从第二层递归开始直到最底层,都无法使用emit向父组件传递事件,因为每一级节点的父组件都是自身,需要传给子组件一个事件,子组件才能使用emit调用。
那么还有其他方式解决以上问题吗

这就不得不说说uni-appvue3了,顺便也说说uni-appvue在递归组件这方面的不同点。

  1. uni-app不支持$listeners,vue3也移除了$listeners,那如何解决呢?下面是不使用$listeners的做法,在v2、uni-app和v3中都适用,无非是v3使用了组合式api。注意看注释,有三个改动点
<template>
  <div>
    <!-- 改动点1,当前节点数据通过点击事件传递 -->
    <div 
      class="node-name" 
      @click.stop="nodeClick(node)"
    >
      {{node.name}}
    </div>
    <div 
      class="children" 
      v-if="node.children && node.children.length"
    >
      <!-- 
        核心:改动点2,
        不再使用$listeners,
        每一级都传递一次node-click,
        使用nodeClick方法接收参数
      -->
      <tree-node 
        v-for="item in node.children" 
        :key="item.id" 
        :node="item" 
        @node-click="nodeClick"
      >
      </tree-node>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'tree-node',
    props: {
      node: Object
    },
    methods: {
      // 改动点3,通过参数接收数据
      nodeClick(node) {
        this.$emit('node-click', node)
      }
    }
  }
</script>

<style scoped>
  .node-name {
    cursor: pointer;
  }
  .children {
    padding-left: 20px;
  }
</style>
  1. 在vue中使用递归组件,无论v2还是v3,都只需要设置一个name属性,即可直接调用,在uni-app中除了设置name属性,还需要使用import引入自身,并使用components注册组件。
// 引入自身
import treeNode from './tree-node.vue'
export default {
  name: 'tree',
  components: { treeNode },
  props: {
    node: Object
  },
  methods: {
    
  },
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3是一种流行的JavaScript框架,用于构建用户界面。它具有响应式数据绑定和组件化的特性,使得开发者可以更轻松地构建交互式的Web应用程序。 Uni-app是一个基于Vue.js的跨平台开发框架,它可以让开发者使用Vue语法编写一次代码,然后通过编译器将代码转换为多个平台(如微信小程序、H5、App等)的应用程序。 onShareAppMessage是uni-app中的一个方法,用于定义小程序页面的转发行为。当用户点击小程序页面的转发按钮时,会触发onShareAppMessage方法,并且可以在该方法中自定义转发的标题、路径和图片等信息。 在Vue3和uni-app中使用onShareAppMessage方法的步骤如下: 1. 在需要使用onShareAppMessage方法的页面组件中,定义一个methods对象,并在该对象中添加一个名为onShareAppMessage的方法。 2. 在onShareAppMessage方法中,可以通过返回一个对象来定义转发的标题、路径和图片等信息。例如: ``` onShareAppMessage() { return { title: '分享标题', path: '/pages/index', imageUrl: 'https://example.com/share.png' } } ``` 上述代码中,定义了转发的标题为"分享标题",路径为"/pages/index",图片为"https://example.com/share.png"。 3. 在小程序页面中,添加一个转发按钮,并绑定点击事件到onShareAppMessage方法。例如: ``` <button @click="onShareAppMessage">转发</button> ``` 上述代码中,当用户点击"转发"按钮时,会触发onShareAppMessage方法。 通过以上步骤,就可以在uni-app中使用onShareAppMessage方法来定义小程序页面的转发行为了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值