Vue3 14.组件03 Event
组件事件监听
在编写博客内容的时候,有时候发现它需要能够和父组件交互,比如想要将博客文章内容文字放大,但是其他部分的仍旧使用默认的字号。
在父组件中可以添加一个postFontSize
ref来实现这个效果:
const posts = ref([ |
在模板中使用它来控制所有博客文章的字体大小:
<div :style="{ fontSize: postFontSize + 'em'}"> |
给<BlogPost>
组件添加一个按钮:
<!-- BlogPost.vue --> |
这个按钮现在没有做任何事情,在点击这个按钮的时候来告诉父组件,应该放大所有博客文章的文字。父组件可以通过v-on
或@
来选择性地监听子组件上抛的事件,就像监听原生DOM事件那样:
<BlogPost |
子组件可以通过内置的$emit
方法,通过传入事件名称来抛出一个事件:
<!-- BlogPost.vue --> |
因为有了@enlarge-text="postFontSize += 0.1"
的监听,父组件会接收这一事件,从而更新postFontSize
的值。
我们可以通过defineEmits
宏来声明需要抛出的事件:
<!-- BlogPost.vue --> |
声明了一个组件可能触发的所有事件,同时还可以让Vue避免将它们作为原生事件监听器隐式地应用于子组件的根元素。
和defineProps
类似,defineEmits
仅可用于<script setup>
之中,并不需要导入,它返回一个等同于$emit
方法的emit
函数。它可以被用于在组件的<script setup>
中抛出事件,因为此处无法直接访问$emit
:
<script setup> |
如果没有使用<script setup>
,可以通过emits
选项定义组件会抛出的事件。可以从setup()
函数的第二个参数,即setup上下文对象上访问到的emit
函数:
export default { |
总结
在组件的模板表达式中,可以直接使用$emit
方法触发自定义事件:
<!-- MyComponent --> |
父组件可以通过v-on
缩写为@
来监听事件:
<MyComponent @some-event="callback" /> |
同样,组件的事件监听器也支持.once
修饰符:
<MyComponent @some-event.once="callback" /> |
像组件与prop一样,事件的名字也提供了自动的格式转换。注意这里触发了一个以camelCase形式命名的事件,但在父组件中可以使用kebab-case形式来监听。与prop大小写格式一样,在模板中也推荐使用kebab-case形式来编写监听器。
和原生DOM事件不一样,组件触发的事件没有冒泡机制。只能监听直接子组件触发的事件。平级组件或者跨越多层嵌套的组件间通信,应该使用一个外部的事件总线,或者使用一个全局状态管理。
事件参数
有时候需要在触发事件时附带一个特定的值。举个例子,想要在<BlogPost>
组件来管理文本会缩放多大,这个场景下,可以给$emit
提供一个额外的参数:
<button @click="$emit('increaseBy', 1)"> |
然后在父组件中监听事件,可以先简单写一个内联的箭头函数作为监听器,此函数会接收到事件附带的参数:
<MyButton @increase-by="(n) => count += n" /> |
也可以使用组件方法的来作为事件处理函数:
<MyButton @increase-by="increaseCount" /> |
该方法会接收到事件传递的参数:
function increaseCount(n) { |
所有传入
$emit()
的额外参数都会被直接传向监听器。如:$emit('foo', 1, 2, 3)
触发后,监听器函数将会受到这三个参数值。
声明触发的事件
在<template>
中使用的$emit
方法不能在组件的<script setup>
部分中使用,应该通过defineEmits()
返回一个相同作用的函数来使用。
<script setup> |
defineEmits
宏不能在子函数中使用。必须直接放置在<script setup>
的顶级作用域下。
如果是显式地使用了setup
函数而不是<script setup>
,则事件需要通过emits
选项定义,emit
函数暴露在setup()
上下文对象中:
export default { |
与setup()
上下文对象中的其他属性一样,emit
可以被安全的解构:
export default { |
这个emits
选项和defineEmits()
宏还支持对象语法。通过Typescript为参数指定类型,它允许对触发事件的参数进行校验:
<script setup lang="ts"> |
如果搭配Typescript使用<script setup>
,可以使用纯类型标注来声明触发的事件:
<script setup lang="ts"> |
尽管事件声明是可选的,但是还是推荐完整地声明所有要触发的事件,这样可以在代码中记录组件的用法。同时事件声明可以让Vue更好地将事件和透传attribute作出区分,从而避免一些由第三方代码触发的自定义DOM事件所导致的边界情况。
如果一个原生事件的名字,如(click)被定义在了
emits
选项中,那么监听器只会监听组件触发的click事件,而不会再响应原生的click
事件。
事件校验
和对props添加类型校验的方式类似,所有触发的事件也可以使用对象形式来描述。
要为事件添加校验,那么事件可以被赋值为一个函数,接受的参数就是抛出事件时传入emit
的内容,返回一个布尔值来表明事件是否合法。
<script setup> |