vue3的组件事件和defineEmits
•
前端
文章目录
-
- 1. 事件基础
-
- 示例
-
- Blog.vue
- BlogPost.vue
- 2. 触发与监听事件
-
- 2.1 触发事件
- 2.2 监听事件
- 3. 事件参数
-
- 3.1 示例1
-
- Blog.vue
- BlogPost.vue
- 3.2 示例2(defineEmits)
-
- MyComponent.vue
- Test.vue
- 4. 声明触发的事件
- 5. 事件校验
-
- 示例1
-
- Blog.vue
- BlogPost.vue
- 示例2(defineEmits)
-
- MyComponent.vue
- Test.vue
1. 事件基础
- 子组件有时候需要与父组件进行交互,子组件需要通知父组件做一些事(比如:prop是单向数据量,子组件不应该直接修改prop绑定的值,而是应该抛出一个事件来通知父组件做出改变)
- 为了解决这个问题,组件实例提供了一个自定义事件系统,父组件可以通过v-on或 @ 来选择性地监听子组件上抛的事件,就像监听原生 DOM 事件那样,当监听到子组件上抛出的事件时,就会执行对应事件绑定的监听函数
- 子组件可以通过调用内置的 $emit 方法,通过传入事件名称来抛出一个事件
- 子组件使用内置的 $emit 方法中,可以使用 $event作为事件参数
- 我们可以通过 emits 选项来声明需要抛出的事件(emits声明选项不是必须的)
- 这声明了一个组件可能触发的所有事件,还可以对事件的参数进行验证
- 还可以让 Vue 避免将它们作为原生事件监听器隐式地应用于子组件的根元素。
- 如果子组件中声明了emits:[‘click’]选项,然后在某个按钮下使用了$emit(‘click’)去触发click事件,则父组件中使用该子组件时,使用@click=‘handleClick’去监听click事件时,不会认为这是原生dom的点击事件,只有当子组件使用$emit(‘click’)触发click事件时,才会触发hanleClick函数。如果不加emits:[‘click’]选项,则只要点击就会触发handleClick事件。
示例

Blog.vue
import BlogPost from './BlogPost.vue'
export default {
name: 'Blog',
components: {
BlogPost
},
data() {
return {
posts: [
{ id: 1, title: 'My journey with Vue' },
{ id: 2, title: 'Blogging with Vue' },
{ id: 3, title: 'Why Vue is so fun' }
],
postFontSize: 1
}
}
}
BlogPost.vue
{{ title }}
export default {
name: 'BlogPost',
props: ['title'],
// 这个emits声明选项不是必须的
emits: ['enlarge-text']
}
2. 触发与监听事件
2.1 触发事件
-
在组件的模板表达式中,可以直接使用 $emit 方法触发自定义事件
-
$emit() 方法在组件实例上也同样以 this.$emit() 的形式可用:
export default { methods: { submit() { this.$emit('someEvent') } } }
2.2 监听事件
-
父组件可以通过 v-on (缩写为 @) 来监听事件
-
组件的事件监听器也支持 .once 修饰符
– 触发事件时建议使用camelCase 形式(驼峰命名,首字母小写),父组件监听是可以使用kebab-case 形式(短横线分隔,推荐)
-
组件触发的事件没有冒泡机制,你只能监听直接子组件触发的事件。
- 平级组件或是跨越多层嵌套的组件间通信,应使用一个外部的事件总线
- 或者使用一个全局状态管理方案。
3. 事件参数
- 有时候会需要在触发事件时附带一个特定的值(事件参数)
- 可以写一个内联的箭头函数作为监听器,此函数会接收到事件附带的参数
- 也可以用一个组件方法来作为事件处理函数,该方法也会接收到事件所传递的参数
- 所有传入 $emit() 的额外参数都会被直接传向监听器。
- 举例来说,$emit(‘foo’, 1, 2, 3) 触发后,监听器函数将会收到这三个参数值。
3.1 示例1

Blog.vue
{{ count }}
count += n" />
import BlogPost from './BlogPost.vue'
export default {
name: 'Blog',
components: {
BlogPost
},
data() {
return {
count: 0
}
},
methods: {
increaseCount(n,m,e) {
console.log(n,m,e); // 1, 2, PointerEvent {isTrusted: true, _vts: 1682821628803, pointerId: 1, width: 1, height: 1, …}
this.count += n
}
}
}
BlogPost.vue
export default {
name: 'BlogPost',
}
3.2 示例2(defineEmits)
- 子组件可以触发自定义事件,
- 父组件使用该子组件时,可以监听该组件的事件,并为监听的事件绑定事件处理函数,
- 当该子组件触发了该事件时,父组件对应的事件处理函数就会执行。

MyComponent.vue
子组件中person: {{ person }}
import { ref,reactive,onUpdated } from 'vue'
/* 1. defineEmits() 宏不能在子函数中使用。它必须直接放置在 的顶级作用域下 */
/* 2. 显式地使用了 setup 函数而不是 ,则事件需要通过 emits 选项来定义,emit 函数也被暴露在 setup() 的上下文对象上 */
const emit = defineEmits(['doUpdate']) /* 可以不需要定义doUpdate, 但建议定义doUpdate, 以此来声明此组件可以被触发的事件 */
function handleClick () {
console.log('click');
emit('doUpdate',e,3,4) /* 使用emit,手动触发doUpdate事件 */
}
const props = defineProps(['person'])
onUpdated(()=>{
console.log('---组件渲染更新了---') /* 当通过触发子组件事件, 父组件监听到该组件的该事件, 修改了person的ref值, 从而组件会更新 */
})
button {
margin: 5px;
}
Test.vue
父组件中person: {{ person }}
import { ref,reactive,computed } from 'vue'
import MyComponent from './MyComponent.vue';
const person = ref({ name: 'demoName', age: NaN})
function handleUpdate(event,payload1,payload2) {
console.log(event); // PointerEvent {isTrusted: true, _vts: 1678062697219, pointerId: 1, width: 1, height: 1, …}
console.log(payload1, payload2);
}
function handleRefresh( p) {
console.log(p); // {name: 'zzhua', age: 18}
person.value = p
}
4. 声明触发的事件
- 组件可以显式地通过 emits 选项来声明它要触发的事件
- 这个 emits 选项还支持对象语法,它允许我们对触发事件的参数进行验证
- 尽管事件声明是可选的,我们还是推荐完整地声明所有要触发的事件。同时,事件声明能让 Vue 更好地将事件和透传 attribute 作出区分,从而避免一些由第三方代码触发的自定义 DOM 事件所导致的边界情况。
- 如果一个原生事件的名字 (例如 click) 被定义在 emits 选项中,则监听器只会监听组件触发的 click 事件而不会再响应原生的 click 事件。
5. 事件校验
- 和对 props 添加类型校验的方式类似,所有触发的事件可以使用字符串,也可以使用对象形式
- 要为事件添加校验,那么事件可以被赋值为一个函数,接受的参数就是抛出事件时传入 this.$emit 的内容,返回一个布尔值来表明事件是否合法
示例1

Blog.vue
{{ count }}
import BlogPost from './BlogPost.vue'
export default {
name: 'Blog',
components: {
BlogPost
},
data() {
return {
count: 0
}
},
handleSubmit(payload) {
console.log(payload);
}
}
BlogPost.vue
export default {
name: 'BlogPost',
emits: {
// 没有校验
click: null,
// 校验 submit 事件
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
},
methods: {
submitForm(email, password) {
this.$emit('submit', { email, password })
}
}
}
示例2(defineEmits)
MyComponent.vue
import { ref, reactive } from 'vue'
const emit = defineEmits({
// 没有校验
click: null,
// 校验 submit 事件
submit: ({ email, password }) => {
if (email && password) {
console.log(email, password);
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
})
function submitForm(email, password) {
emit('submit', { email, password })
}
button {
margin: 5px;
}
Test.vue
import { ref,reactive,computed } from 'vue'
import MyComponent from './MyComponent.vue';
本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://www.net2asp.com/e4c74182ea.html
