Vue中递归组件时的阻止冒泡事件和$emit失效问题解决

本文介绍了在Vue中使用递归组件构建侧边栏时遇到的事件冒泡问题。通过在点击事件中添加`.stop`修饰符解决了冒泡问题,但随后发现子菜单的`$emit()`事件失效。解决方法是在递归组件上使用`v-on=$listeners`,使得子组件能正确传递事件。最终实现了递归组件的正常工作。
摘要由CSDN通过智能技术生成

今天在写一个侧边栏时,用到了递归组件,代码如下

<template>
  <div>
    <ul class="rightList-container">
      <li v-for="(item, i) in list" :key="i" @click="handleClick(item)">
        <span :class="{ active: item.isSelected }">{{ item.name }}</span>
        <span
          v-if="item.aside"
          class="aside"
          :class="{ active: item.isSelected }"
          >{{ item.aside }}</span
        >
        <!-- 这里的 list 会有子list , 而子list 的结构和样式和当前一样,因此这里就使用 递归组件 -->
        <RightList :list="item.childrenList"></RightList>
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  name: "RightList", // 给当前组件取个名字,方便递归的时候自己调用自己
  props: {
    // 右边列表数据的格式 应该是 [{name : xxx  , isSelected : xx , childrenList : {name : xxx , isSelected: xx , children : {...}}}]
    list: {
      type: Array,
      default: () => [],
    },
  },
  methods: {
    handleClick(item) {
      // 右边栏选项点击以后抛出一个事件,只有当当前是未选中状态,点击切换到选中状态才处理,抛出事件由父组件处理
      this.$emit("select", item);
    },
  },
};

但是出现一个问题就是点击子菜单栏(递归的二级菜单栏)会出现冒泡事件, 如下点击一次,会把其一级菜单栏也打印出来
在这里插入图片描述
解决方法为 vue 处理事件冒泡的方法, 给click事件添加 .stop 阻止冒泡,如下

<template>
  <div>
    <ul class="rightList-container">
      <li v-for="(item, i) in list" :key="i" @click.stop="handleClick(item)">
        <span :class="{ active: item.isSelected }">{{ item.name }}</span>
        <span
          v-if="item.aside"
          class="aside"
          :class="{ active: item.isSelected }"
          >{{ item.aside }}</span
        >
        <!-- 这里的 list 会有子list , 而子list 的结构和样式和当前一样,因此这里就使用 递归组件 -->
        <RightList :list="item.childrenList"></RightList>
      </li>
    </ul>
  </div>
</template>

解决完冒泡事件后出现了子菜单栏点击发送的 $emit() 失效,具体原因可见这篇博客:https://blog.csdn.net/weixin_44132285/article/details/120323217

解决方法为给递归的子组件添加 v-on=“$listeners”,如下:

<template>
  <div>
    <ul class="rightList-container">
      <li v-for="(item, i) in list" :key="i" @click.stop="handleClick(item)">
        <span :class="{ active: item.isSelected }">{{ item.name }}</span>
        <span
          v-if="item.aside"
          class="aside"
          :class="{ active: item.isSelected }"
          >{{ item.aside }}</span
        >
        <!-- 这里的 list 会有子list , 而子list 的结构和样式和当前一样,因此这里就使用 递归组件 -->
        <RightList :list="item.childrenList" v-on="$listeners"></RightList>
      </li>
    </ul>
  </div>
</template>

就完美解决啦~

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值