前提
Vue项目中常见有父子组件之间交互的情况,假设本文中我们叫 父组件为 father,子组件为 son, 那么最常见有以下几种情况:
A. son 获取 father 中的 数据
B. son 调用 father 中的 函数
C. father 获取 son 中的 数据
D. father 调用 son 中的 函数
下面我来讲讲 props、$ref、$emit 怎么使用,使其达到上面几种目的:
1. son 获取 father 中的 数据
最常见的就是使用 props,即 father 在使用 son 的时候,以属性值的形式传递给 son,代码如下:
<!-- father -->
<template>
<div>
<h1>I am your father!</h1>
<son message="Hello son!"></son> //father 通过自定义属性 message 传递数据到 son
</div>
</template>
<script>
import son from '../components/son.vue'
export default {
components: {son},
}
</script>
<!-- son -->
<template>
<h3>{{message}}</h3>
</template>
<script>
export default {
props: ['message'] //这里的 message 名字就是 father 使用 son 时自定义的属性名字
}
</script>
注意:
A. 这里有时候我们需要 message 是动态的,那么可以在 father 中设置一个变量,并将这个变量绑定到 message 属性中,father 如下:
<!-- father -->
<template>
<div>
<h1>I am your father!</h1>
<son :message="message"></son> //father 通过自定义属性 message 传递数据到 son
</div>
</template>
<script>
import son from '../components/son.vue'
export default {
data() {
return {
message: 'Hello son!',//这里的 message 变量可以通过 api 或者业务逻辑获取到动态数据,son 获取到后可以自己存储到 data 中的一个变量来使用
};
},
components: {son},
}
</script>
B. props 的传值是单向的,只能从 father 传值到 son
2. son 调用 father 中的 函数
在 son 组件中使用 $emit 可以调用 father 中的函数,具体就是在 father 中使用 son 的时候,以属性的形式绑定上 father 的函数,然后就可以在 son 中调用了,代码如下:
<!-- father -->
<template>
<div>
<h1>I am your father!</h1>
<son @showMessage="showMsg"></son> //father 绑定自定义函数 showMessage,这里可以理解为回调钩子函数
</div>
</template>
<script>
import son from '../components/son.vue'
export default {
data() {
return {
message: {},//接收来自 son 的数据
}
},
components: {son},
methods:{
showMsg(msg){
//son 回调 showMessage 函数其实触发的是 father 定义的 showMsg 函数
this.message = msg;
console.log(msg);//这里输出 Hello father!
}
}
}
</script>
<!-- son -->
<template>
<h3>I am son !</h3>
</template>
<script>
export default {
mounted: function () {
//在 son 初始化后调用 father 绑定的 showMessage 函数,并传递一个字符串作为参数
//实际情况,这里回调 father 的函数,常见的是 son 中用户的点击事件触发的
//this.$emit 第一个参数是 father 使用 son 时绑定的自定义的属性名,第二个参数是回调函数的参数,可以是一个对象
this.$emit('showMessage', 'Hello father!');
}
}
</script>
3. father 获取 son 中的 数据 和 father 调用 son 中的 函数
之所以把这两种情况一起讲,是因为原理都一样的。father 在使用 son 的时候,绑定属性 ref,并给一个唯一key值,这个key值相当于是唯一标识符,代码如下:
<!-- father -->
<template>
<div>
<h1>I am your father!</h1>
<son ref="myson"></son> //father 在 使用 son 时添加 ref 属性,并给予唯一标识符 myson
<span @click="getFromSon">点我试试</span>
</div>
</template>
<script>
import son from '../components/son.vue'
export default {
data() {
return {
message: {},//接收来自 son 的数据
}
},
components: {son},
methods:{
getFromSon(){
//this.$refs.myson 获取到 son 的 vue 对象,这里的 myson 唯一标识符用处就体现在这里
this.message = this.$refs.myson.message;//将 son 中的 message 变量赋值给 father 中的 message
this.$refs.myson.showMessage();//调用 son 中函数,输出: Father come to see me ! Haha !
}
}
}
</script>
<!-- son -->
<template>
<h3>I am son !</h3>
</template>
<script>
export default {
data(){
return{
message: 'I am your son !'
}
},
methods:{
showMessage(){
console.log('Father come to see me ! Haha !')
}
}
}
</script>
总结:
1. props 用于简单的 father 向 son 传值
2. $ref 可以看做是引用组件的集合,只要在 father 中 使用 son 时标记了 ref 属性,且给予了唯一标识符,那么 father 就可以通过 this.$refs.唯一标识符 的形式获取到 son 的 vue 对象,获取到对象后,就可以获取对象里的值 和 调用函数
3. $emit 用于 son 回调 father 中的函数,实际常见情况比如:
假设 搜索条件的组件 叫 son, 使用 搜索条件组件的叫 father,当 son 中某个搜索条件变了,那么需要回调 father 页面,并将改变的参数集合给它 去刷新页面数据
4. 实际情况中还有 兄弟组件之间的交互,其实可以结合 $ref 和 $emit 两者来实现兄弟组件的交互