爷孙组件的事件传递和 vue2 的写法不一样了
$listeners 在 3 中删除了,将事件合并到了 $attrs 中
需要使用 v-bind 递归绑定 $attrs 传递事件而不是 v-on
$attrs 里的事件名会转为驼峰,并且自动加上 on 前缀
例:
@sort 在 $attrs 中的 key 为 onSort
@on-sort 在 $attrs 中的 key onOnSort
emit 里声明的事件,将从 $attrs 里删除,无法继续递归传递
移除$listeners
https://v3-migration.vuejs.org/zh/breaking-changes/listeners-removed.html
$listeners 对象在 Vue 3 中已被移除。事件监听器现在是 $attrs 的一部分:
{
text: '这是一个 attribute',
onClose: () => console.log('close 事件被触发')
}
emit 声明的事件会从 $attrs 中删除
其实和 prop 一样了
https://cn.vuejs.org/api/options-state.html#emits
注意,emits 选项会影响一个监听器被解析为组件事件监听器,还是原生 DOM 事件监听器。
被声明为组件事件的监听器不会被透传到组件的根元素上,且将从组件的 $attrs 对象中移除。
详见透传 Attributes。
【vue3】爷孙组件事件传递
<!-- 父组件 -->
<template>
<div class="parent-root">
<child @sort="sort"></child>
</div>
</template>
<!-- 子组件 -->
<template>
<div class="child-root">
<!-- 这里 sort 不要写在 emit 声明中 -->
<grandson v-bind="$attrs"></grandson>
</div>
</template>
<!-- 孙组件 -->
<template>
<div class="grandson-root">
<button @click="$emit('sort')">触发顶级父组件的 sort</button>
</div>
</template>
【vue3】递归组件事件传递
<!-- 父组件 -->
<template>
<div class="parent-root">
<div v-if="children.length">
<!-- 监听递归组件传递的 sort 事件并触发 -->
<child
v-for="item in children"
:key="item.id"
@sort="sort">
</child>
</div>
</div>
</template>
<!-- 子组件 -->
<template>
<div class="child-root">
<button @click="$emit('sort')">触发顶级父组件的 sort</button>
<div v-if="children.length">
<!-- v-bind="$attrs" -->
<!-- 使事件继续向下递归传递" -->
<child
v-for="item in children"
:key="item.id"
v-bind="$attrs">
</child>
</div>
</div>
</template>