Vue $emit() 方法

通过 Vue 中内置的 $emit() 方法,我们可以在子组件中创建一个可以在父元素中捕获的自定义事件。

Props 用于将数据从父元素发送到子组件,$emit() 用于执行将信息从子组件传递到父组件。

我们接下来要做的事情的目的是在父 App.vue 中而不是在当前发生更改的 FoodItem.vue 子组件中更改食物的 'favorite' 状态。

之所以在 App.vue 中而不是在 FoodItem.vue 中更改收藏夹状态,是因为 App.vue 是收藏夹状态的存储位置,因此需要更新。在一个更大的项目中,数据可能来自我们在 App.vue 中连接到的数据库,我们希望组件发生更改以在数据库中进行更改,因此我们需要从子组件返回到父组件。


Emit 一个自定义事件

需要将信息从组件发送到父级,我们使用内置的方法 $emit() 来实现这一点。

我们已经在 FoodItem.vue 组件中有了 toggleFavorite 方法,该方法在单击 toggle 按钮时运行。现在,让我们删除现有的行,并添加一行来发出我们的自定义事件 'toggle-favorite':

FoodItem.vue:

  1. methods: {
  2. toggleFavorite() {
  3. this.foodIsFavorite = !this.foodIsFavorite;
  4. this.$emit('toggle-Favorite');
  5. }
  6. }

我们可以选择自定义事件的名称,但对 Emit 发送事件使用 kebab-case 规则写是正常的。


接收一个 Emit 事件

自定义的 Emit 事件 'toggle-favorite' 现在是从 FoodItem.vue 组件发出的,但我们需要监听 App.vue 父级中的事件,并调用一个执行某些操作的方法,以便我们可以看到事件发生了。

在创建组件的 App.vue 中,我们使用缩写 @ 而不是 v-on: 来监听事件:

实例

App.vue 中监听 'toggle-favorite' 事件:

  1. <food-item
  2. v-for="x in foods"
  3. :key="x.name"
  4. :food-name="x.name"
  5. :food-desc="x.desc"
  6. :is-favorite="x.favorite"
  7. @toggle-favorite="receiveEmit"
  8. />

当我们的自定义 'toggle-favorite' 事件发生时,我们需要在 App.vue 中创建 'testEmit' 方法,这样我们就可以看到事件发生了:

  1. methods: {
  2. receiveEmit() {
  3. alert('Hello World!');
  4. }
  5. }

更改父级中食物项目的 'favorite' 状态

我们现在有一个事件,当从子组件单击 'Favorite' 按钮时,它会通知 App.vue

当单击 'favorite' 按钮时,我们想更改 App.vue 中 'foods' 数组中的 'Favorite' 属性以获得正确的食物。为此,我们将食品名称从 FoodItem.vue 发送到 App.vue,因为这对每个食品都是唯一的:

FoodItem.vue:

  1. methods: {
  2. toggleFavorite() {
  3. this.$emit('toggle-favorite', this.foodName);
  4. }
  5. }

现在,我们可以在 App.vue 中接收食物项目名称,作为 'toggle-favorite' 事件发生时调用的方法的参数,如下所示:

实例

App.vue:

  1. methods: {
  2. receiveEmit(foodId) {
  3. alert( 'You clicked: ' + foodId );
  4. }
  5. }

现在我们知道点击了什么食物,我们可以更新 'foods' 数组中正确食物的 'favorite' 状态:

App.vue:

  1. methods: {
  2. receiveEmit(foodId) {
  3. const foundFood = this.foods.find(
  4. food => food.name === foodId
  5. );
  6. foundFood.favorite = !foundFood.favorite;
  7. }
  8. }

在上面的代码中,数组方法 'find' 遍历 'foods' 数组,查找一个 name 属性等于我们单击的食物项目的对象,并将该对象返回为 'foundFood'。之后,我们可以将 'foundFood.health' 设置为与以前相反的值,以便在 truefalse 之间切换。

'foods' 数组中正确的食物现在会更新其 'favorite' 状态。剩下的唯一事情就是更新表示最喜欢的食物的图片。

因为食物项目组件已经从 'foods' 数组中以 'favorite' 状态创建,并从 App.vue 中作为道具 'is-favorite' 发送,我们只需要从 v-show 中引用 FoodItem.vue 中的这个 'isFavorite ' pros,其中 <img> 元素用于更新图像:

  1. <img src="/img_quality.svg" v-show="isFavorite">

我们还可以删除 FoodItem.vue 中的 'foodIsFavorite' 数据属性,因为它已不再使用。

实例

在最后一个实例代码中,可以以与以前类似的方式切换食物的喜爱状态,但现在在 App.vue 中的正确位置修改了喜爱状态。


'emits' 选项

与我们在 FoodItem.vue 组件中声明 props 的方式相同,我们也可以通过使用 Vue的 'emits' 选项来记录组件发出的内容。

Props 必须在组件中声明,而 emits 只是建议记录下来。

这就是我们如何在 FoodItem.vue 组件中记录我们的 emit:

  1. <script>
  2. export default {
  3. props: ['foodName','foodDesc','isFavorite'],
  4. emits: ['toggle-favorite'],
  5. methods: {
  6. toggleFavorite() {
  7. this.$emit('toggle-favorite', this.foodName);
  8. }
  9. }
  10. };
  11. </script>

当 emits 被记录下来时,其他人会更容易使用该组件。