vue 递归组件 递归组件中的插槽

本文介绍了如何在Vue中创建一个可自定义渲染的递归树形组件。组件通过插槽允许外部定义每项内容,并通过render函数处理动态插槽和数据传递,实现了树结构数据的递归显示。当点击树节点时,会触发事件并传递节点数据。
摘要由CSDN通过智能技术生成

需求:

        在开发中需要一个公共组件Tree(树),接受的数据是典型的树结构数据,当前项数据是       一个对象,如果有子节点,拥有一个children属性。我并不希望每一项的数据展现形式是定死的,而是通过插槽能够自定义。

假设:

<template>
  <ul class="tree-wrapper">
    <li v-for="(item, index) in list" :key="index" @click.stop="change(item)">
      <div class="content" :class="{ active: item.active }">
        <slot :row="item">{{ item.name }}</slot>
      </div>
      <Tree :list="item.children" @change="change">
        <slot :row="item">{{ item.name }}</slot>
      </Tree>
    </li>
  </ul>
</template>

<script>
export default {
  name: 'Tree',
  props: {
    list: {
      type: Array,
      default: () => [],
    },
  },
  methods: {
    change(item) {
      if (!item.active) {
        this.$emit('change', item);
      }
    },
  },
};
</script>
<template>
  <div class="blog-type-wrapper" v-loading="isLoading">
    <Tree :list="typeList" @change="handleChange('categoryID', $event)">
      <template #default="{ row }">
        <span class="name">{{ row.name }}</span>
        <span class="num">{{ row.articleCount }}篇</span>
      </template>
    </Tree>
  </div>
</template>

问题:

        在组件内部可以通过定义name标识组件,然后使用name名称作为组件名称,实现递归调用,但是递归引用处的插槽内容如何通过外部定义呢?递归内部的数据又如何传递呢?

 解决:

        使用模板的形式不是很好处理此问题,使用render函数替代模板可以很好的解决


<script>
export default {
  render(h) {
    //c2函数用于处理动态的插槽部分
    const c2 = (item) => {
      const arr = [
        h(
          'div',
          {
            class: {
              content: true, //静态类名
              active: item.active, //动态类名
            },
          },
          this.$scopedSlots.default
            ? this.$scopedSlots.default({ row: item }) //相当于作用域插槽
            : item.name //相当于插槽默认值
        ),
      ];
      //如果存在子级,使用递归处理
      if (item.children && item.children.length > 0) {
        arr.push(c1(item.children));
      }
      return arr;
    };

    //c1函数用于处理固定结构部分(例如ul为父级,每个数据项对应一个li子级)
    const c1 = (list) => {
      const lis = list.map((item, index) => {
        return h(
          'li',
          {
            attrs: {
              key: index, //key标识
            },
            on: {
              click: (event) => {
                event.stopPropagation(); //阻止事件冒泡,为了精确处理每一项子级的事件
                if (!item.active) {
                  this.$emit('change', item);
                }
              },
            },
          },
          c2(item)
        );
      });

      const ul = h(
        'ul',
        {
          class: {
            'tree-wrapper': true,
          },
        },
        lis
      );
      return ul;
    };

    return c1(this.$attrs.list);
  },
};
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值