Skip to content

自定义事件

自定义事件的核心思想,子组件传递数据给父组件。

另外,父组件传递给子组件的数据,子组件不能去改,此时子组件也可以通过自定义事件的形式,去通知父组件,让父组件即时的更新数据。

快速上手

这里以评分组件为例:

vue
<template>
  <div class="rating-container">
    <span v-for="star in 5" :key="star" class="star" @click="setStar(star)">
      {{ rating >= star ? '★' : '☆' }}
    </span>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const rating = ref(0) // 表示几颗星

const emits = defineEmits(['update-rating'])

function setStar(newStar) {
  rating.value = newStar
  // 我们需要将最新的星星状态的值传递给父组件
  // 触发父组件的 update-rating 事件
  emits('update-rating', rating.value)
}
</script>

<style scoped>
.rating-container {
  display: flex;
  font-size: 24px;
  cursor: pointer;
}

.star {
  margin-right: 5px;
  color: gold;
}

.star:hover {
  color: orange;
}
</style>

在上面的评分组件中,我们需要将子组件 rating 的状态值传递给父组件,通过触发父组件所绑定的 update-rating 事件来进行传递。

vue
<template>
  <div class="app-container">
    <h1>请对本次服务评分:</h1>
    <Rating @update-rating="handleRating" />
    <p v-if="rating > 0">你当前的评价为 {{ rating }} 颗星</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import Rating from './components/Rating.vue'
const rating = ref(0)

function handleRating(newRating) {
  // 更新父组件的数据就可以了
  rating.value = newRating
}
</script>

<style scoped>
.app-container {
  max-width: 600px;
  margin: auto;
  text-align: center;
  font-family: Arial, sans-serif;
}

p {
  font-size: 18px;
  color: #333;
}
</style>

父组件在使用子组件的时候,就为子组件绑定了自定义事件,本例中是 update-rating 事件,当子组件触发该事件时,就会执行该事件所对应的事件处理函数 handleRating. 事件处理函数的形参就能够接收到子组件传递过来的数据。

事件相关细节

模板中使用$emit()触发事件

在组件的模板中,可以直接使用 $emit 去触发自定义事件。例如上面的评分的组件例子,可以这么写:

vue
<span v-for="star in 5" :key="star" class="star" @click="$emit('update-rating', star)">
  {{ rating >= star ? '★' : '☆' }}
</span>

和前面所介绍的 Props 类似,自定义事件也是支持校验的。这里的校验主要是对子组件要传递给父组件的值进行校验。

emit校验

要添加校验,需要书写为对象的形式,对象的键是事件名,值是校验函数,校验函数所接收的参数就是 emit 触发事件时要传递给父组件的参数,需要返回一个布尔值来说明传递的值是否通过了校验。

vue
<script setup>
const emit = defineEmits({
  // 没有校验
  click: null,

  // 校验 submit 事件
  submit: ({ email, password }) => {
    if (email && password) {
      return true
    } else {
      console.warn('Invalid submit event payload!')
      return false
    }
  }
})

function submitForm(email, password) {
  emit('submit', { email, password })
}
</script>

例如还是拿刚才的评分组件来举例:

js
defineProps(['rating'])
const emits = defineEmits({
  'update-rating': (value) => {
    if (value < 1 || value > 5) {
      console.warn('传递的值有问题!!!')
      return false
    }
    return true
  }
})

function setStar(newStar) {
  // 我们需要将最新的星星状态的值传递给父组件
  // 触发父组件的 update-rating 事件
  emits('update-rating', 100)
}

-EOF-

MIT License