Vue $emit() 方法
使用 Vue 内置的 $emit()
方法,我们可以在子组件中创建一个自定义事件,该事件可以在父元素中捕获。
Props 用于将数据从父元素发送到子组件,而 $emit()
则用于做相反的事情:将信息从子组件传递到父组件。
下一步的目的是让食物项的“收藏”状态在父组件 App.vue
中更改,而不是像现在这样在 FoodItem.vue
子组件中发生更改。
将收藏状态更改的原因是在 App.vue
中而不是在 FoodItem.vue
中,是因为 App.vue
是收藏状态最初存储的地方,所以需要更新。在一个更大的项目中,数据可能来自我们与 App.vue
连接的数据库,并且我们希望通过组件的更改来修改数据库,所以我们需要从子组件通信回父组件。
发出自定义事件
需要将信息从组件发送到父组件,我们使用内置方法 $emit()
来实现。
我们在 FoodItem.vue
组件的 toggleFavorite
方法中已经处理了点击切换按钮时需要发送信息。现在,让我们删除现有的行,并添加一行来发出我们的自定义事件 'toggle-favorite'。
FoodItem.vue
:
methods: {
toggleFavorite() {
this.foodIsFavorite = !this.foodIsFavorite;
this.$emit('toggle-Favorite');
}
}
我们可以选择自定义事件的名称,但通常使用 kebab-case 来命名 emit 事件。
接收 emit 事件
自定义 emit 事件 'toggle-favorite' 现在从 FoodItem.vue
组件发出,但我们需要在 App.vue
父组件中监听该事件,并调用一个方法来执行一些操作,以便我们能看到事件已经发生。
我们在 App.vue
中创建组件的地方,使用简写 @
而不是 v-on:
来监听事件。
示例
监听 App.vue
中的 'toggle-favorite' 事件
<food-item
v-for="x in foods"
:key="x.name"
:food-name="x.name"
:food-desc="x.desc"
:is-favorite="x.favorite"
@toggle-favorite="receiveEmit"
/>
当我们的自定义 'toggle-favorite' 事件发生时,我们需要在 App.vue
中创建 receiveEmit
方法,以便我们能看到事件已经发生。
methods: {
receiveEmit() {
alert('Hello World!');
}
}
运行示例 »
更改父组件中的食物项“收藏”状态
我们现在有一个事件,当从子组件点击“收藏”按钮时,该事件会通知 App.vue
。
当点击“收藏”按钮时,我们希望在 App.vue
中更改 'foods' 数组中正确食物项的 'favorite' 属性。为此,我们将食物项名称从 FoodItem.vue
发送到 App.vue
,因为每个食物项的名称都是唯一的。
FoodItem.vue
:
methods: {
toggleFavorite() {
this.$emit('toggle-favorite', this.foodName);
}
}
我们现在可以在 App.vue
中接收食物项名称,作为当 'toggle-favorite' 事件发生时调用的方法的参数,如下所示。
现在我们知道了哪个食物项被点击了,我们可以在 'foods' 数组中更新正确食物项的 'favorite' 状态。
App.vue
:
methods: {
receiveEmit(foodId) {
const foundFood = this.foods.find(
food => food.name === foodId
);
foundFood.favorite = !foundFood.favorite;
}
}
在上面的代码中,数组方法 'find' 遍历 'foods' 数组,查找 name 属性等于我们点击的食物项的对象,并返回该对象作为 'foundFood'。之后,我们可以将 'foundFood.health' 设置为与之前相反的值,以便它在 true
和 false
之间切换。
在此处了解有关 JavaScript 数组方法 'find' 的更多信息:这里。
在此处了解有关 JavaScript 箭头函数的更多信息:这里。
现在 'foods' 数组中的正确食物的“favorite”状态已更新。唯一剩下的就是更新表示收藏食物的图像。
因为食物项组件已经使用“foods”数组中的“favorite”状态创建,并作为 prop 'is-favorite' 从 App.vue
发送,我们只需要在 FoodItem.vue
中引用该 'isFavorite' prop,并在 v-show
中用于 <img>
元素来更新图像。
<img src="/img_quality.svg" v-show="isFavorite">
我们还可以删除 FoodItem.vue
中的 'foodIsFavorite' 数据属性,因为它不再使用。
The 'emits' Option
与我们在 FoodItem.vue
组件中声明 props 的方式相同,我们也可以使用 Vue 的 'emits' 选项来记录组件发出的内容。
Props 必须在组件中声明,而 emits 仅建议记录。
以下是我们如何在 FoodItem.vue
组件中记录 emit 的方式。
<script>
export default {
props: ['foodName','foodDesc','isFavorite'],
emits: ['toggle-favorite'],
methods: {
toggleFavorite() {
this.$emit('toggle-favorite', this.foodName);
}
}
};
</script>
当 emit 被记录时,组件对于其他人来说会更容易使用。