目录
前言
一、基本语法
1. 子组件触发
2. 父组件监听
二、 事件参数
1. 传值
2. 接收值
三、 事件校验
四、注意事项
前言
组件事件是 Vue 组件之间进行通信的一种方式。它允许一个组件触发一个自定义事件,并且其他组件可以监听并响应这个事件。
一、基本语法
1. 子组件触发
子组件触发自定义的事件有两种方式。
- 模板表达式中
在组件的模板表达式中,可以直接使用 $emit
方法触发自定义事件,例如:
<!-- SonCom -->
<button @click="$emit('someEvent')">click me</button>
- <script setup> 里
显式地通过 defineEmits() 宏来声明它要触发的事件。注意,defineEmits只等在<script setup>
的顶级作用域下使用,不能在别的函数里。
科普一下:在计算机编程中,宏(Macro)通常是一种预处理指令或代码片段,用于在编译过程之前进行文本替换和代码生成。宏可以帮助简化代码编写、提高代码的复用性和可维护性。
然后使用defineEmits()
返回的跟模板里面的 $emit 相同作用的函数来触发。
<script setup>
// 声明
const emit = defineEmits(['touchFather', 'submitFather'])
// 触发
function buttonClick() {
emit('touchFather')
}
</script>
- 非 <script setup> 里
事件需要通过 emits 选项来定义,emit
函数也被暴露在 setup()
的上下文对象上。
export default {
emits: ['inFocus', 'submit'],
setup(props, ctx) {
ctx.emit('submit')
}
}
2. 父组件监听
和Vue2一样,父组件可以通过 v-on
(缩写为 @
) 来监听事件:
<SonCom @some-event="callback" />
ps:事件名可以用驼峰形式,但是在模板中是推荐使用kebab-case 形式来编写。
二、 事件参数
如果我们需要再触发事件的时候给父组件传特定的值,就可以提供给 $emit 额外的参数。
1. 传值
- 模板里传值
<button @click="$emit('chooseA', 1)">
chooseA
</button>
- script里传值
<script setup>
// 声明
const emit = defineEmits(['touchFather', 'submitFather'])
// 触发并传值
function buttonClick() {
emit('touchFather', num)
}
</script>
所有传入
$emit()
或emit()
的额外参数都会传过去,传参不限制个数。
2. 接收值
- 模板里接收值
<SonCom @touch-father="(num) => count = num" />
- 方法里接收值
<SonCom @touch-father="handleNum" />
<script>
function handleNum(num) {
count.value += num
}
</script>
三、 事件校验
事件也可以像Props一样来进行校验。只需要将上面的数组换成对象。对象里事件被赋值为一个函数。接受的参数就是抛出事件时传入 emit
的内容,返回一个布尔值来表明事件是否合法。
<script setup>
const emit = defineEmits({
// 没有校验
touchFather: null,
// 校验 submitFather 事件
submitFather: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
})
function submitForm(email, password) {
emit('submitFather', { email, password })
}
</script>
示例:
子组件:校验并且传参不符合校验规则
<template>
<div>
<button @click="submitForm">子传父</button>
</div>
</template>
<script setup>
const obj = {
email: '',
password: ''
}
const emit = defineEmits({
// 没有校验
touchFather: null,
// 校验 submitFather 事件
submitFather: ({ email, password }) => {
if (email && password) {
return true
}
console.log('传参无效!')
return false
}
})
function submitForm() {
emit('submitFather', obj)
}
</script>
父组件:
<template>
<div>
<ChildComponent @submit-father="handle" />
</div>
</template>
<script setup>
import ChildComponent from './ChildComponent.vue'
function handle({ email, password }) {
console.log('父组件——', email, password)
}
</script>
运行结果:
传参失败,并且Vue报错。
如果给obj值通过校验:
<template>
<div>
<button @click="submitForm">子传父</button>
</div>
</template>
<script setup>
const obj = {
email: 123,
password: 123
}
const emit = defineEmits({
// 没有校验
touchFather: null,
// 校验 submitFather 事件
submitFather: ({ email, password }) => {
if (email && password) {
return true
}
console.log('传参无效!')
return false
}
})
function submitForm() {
emit('submitFather', obj)
}
</script>
结果:
四、注意事项
1. 组件触发的事件没有冒泡机制。
2. 如果一个原生事件的名字 (例如 click
) 被定义在 emits
选项中,则监听器只会监听组件触发的 click
事件而不会再响应原生的 click
事件。