通信指的是组件之间的数据传递。
但问题是子组件接收到的数据子组件无法修改,只有父组件才能修改,因为 Vue 使用了一种叫做单向数据流(unidirectional data flow)的概念。
有两种修改接收到的数据的方法:
1 第一种方法是简单地将接收到的数据作为另外一个内部数据的初始数据,然后修改另外的变量,举例:
子组件接收到 isFavorite
,想要修改:
props: ['name', 'phoneNumber', 'emailAddress', 'isFavorite'],
data() {
return {
// 子组件虽然不能修改接收到的 isFavorite ,
// 但是却可以修改 friendIsFavorite
friendIsFavorite: this.isFavorite,
}
}
2 另一种方法是让父组件知道我们想改变某个数据,父组件更改数据后,将更新后的数据传回子组件, 这是一种重要的模式。可以通过发出自定义事件 (emit custom events) 实现这一模式。通常,点击一个按钮,按钮就会发出一个点击事件,然后我们就可以监听这个事件,Vue 中的自定义事件也是如此。
对于第 2 种方法,可以通过调用 Vue 的内建方法this.$emit
实现。
<script>
export default {
// 在 props 中定义此组件接收哪些 props
// 定义 props 属性是强制要求
props: ['name', 'phoneNumber', 'emailAddress', 'isFavorite'],
// 在 emits 中定义组件最终将在某个时间点
// 发出哪些自定义事件。
// 此定义可选
// emits: ['toggle-favorite'],
// 另一种定义方法,进一步验证custom events
// 此定义可选
// 虽然只是一种建议,
// 但是下述的定义可以提高代码的可读性,
// 对代码调试也有帮助
emits: {
// 'toggle-favorite' 是一个事件,
// 应该被一个函数处理,该函数接收一个id参数。
'toggle-favorite': function(id) {
if (id) {
return true;
} else {
console.warn('Id is missing!');
return false;
}
}
},
data() {
return {
detailsAreVisible: false,
};
},
methods: {
toggleDetails() {
this.detailsAreVisible = !this.detailsAreVisible;
},
toggleFavorite() {
this.$emit("toggle-favorite", this.id);
}
}
}
</script>
上面的代码,定义 emits
不同于定义 props
, 后者是强制要求,定义 emits
只是一种建议的做法,相当于对当前组件进行一些文档注释,让其他开发人员清楚当前组件是如何工作的,有哪些事件可以监听。
this.$emit('toggle-favorite', this.id)
'toggle-favorite'
是事件名称,约定所有的事件名称都采用 kebab-case 标记法。这行代码是说,当组件发出'toggle-favorite'
事件时,此事件将携有数据,这里是 this.id
, this.id
将是监听此事件的方法的第 1 个参数。
父组件的事件监听方法可以修改某些数据,而当数据发生变化时,Vue 将会检测到这种变化,然后自动将更新后的数据传回子组件并同时更新 UI。
上述例子中的父组件的代码如下:
<template>
<ul>
<friend-contact v-for="friend in friends"
:key="friend.id"
:id="friend.id"
:name="friend.name"
:phone-number="friend.phone"
:email-address="friend.email"
:is-favorite="friend.isFavorite"
@toggle-favorite="toggleFavoriteStatus">
</friend-contact>
</ul>
</template>
<script>
export default {
data() {
return {
friends: [
{
id: "julie",
name: "Julie Jons",
phone: "123445",
email: "[email protected]",
isFavorite: true,
},
],
};
},
computed: {},
methods: {
toggleFavoriteStatus(friendId) {
const identifiedFriend = this.friends.find(friend => friend.id === friendId);
identifiedFriend.isFavorite = !identifiedFriend.isFavorite;
}
},
};
</script>