在B站看到一个Vue2的进阶视频,提到了子组件向父组件传递数据可以使用prop的方式,觉得很诧异,因为官方文档里面提到的是单向下行绑定。
父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
但是根据实际使用的情况,有时候却需要这么操作,所以总结起来的子组件向父组件传递数据有两种方式prop和emit。
首先总结一下传统的emit方式:
// 父组件 School.vue
<template>
<div class="school-style">
<h2>学校名称:{{ schoolName }}</h2>
<h2>学校地址:{{ address }}</h2>
<h3>来自子组件Emit:{{ stuNameEmit }}</h3>
<Student @CustomEventName="getDataFromSonByEmit"
></Student>
</div>
</template>
<script>
import Student from "./Student";
export default {
name: "School",
components: {
Student: Student,
},
data() {
return {
schoolName: "浙江大学",
address: "杭州紫金港",
teacherName: "陈老师",
stuNameEmit: "",
};
},
methods: {
getDataFromSonByEmit(param) {
console.log("来自子组件的数据emit:", param);
this.stuNameEmit = param;
},
},
};
</script>父组件通过getDataFromSonByEmit这个函数(方法)来监听并处理子组件Student的自定义方法CustomEventName。进而可以在getDataFromSonByEmit这个函数内接收子组件“发送”来的数据并做处理。
// 子组件 Student.vue
<template>
<div class="student-style">
<h2>学生姓名:{{ studentName }}</h2>
<h2>学生年龄:{{ age }}</h2>
<button @click="sendDataByEmit">emit方式向父组件传送数据</button>
</div>
</template>
<script>
export default {
name: "Student",
data() {
return {
studentName: "张三",
age: 18,
};
},
props: {
getFromSon: {
type: Function,
},
},
methods: {
sendDataByEmit() {
this.$emit("CustomEventName", this.studentName);
},
},
};
</script>
<style scoped>
.student-style {
background-color: pink;
margin: 20px;
}
</style>子组件的自定义方法CustomEventName,需要在子组件内被触发,触发之后通过this.$emit(自定义事件名称, 携带的参数)的方式向父组件通知并携带参数。
所以核心的代码:
//父组件
//父组件通过一个方法监听子组件的自定义事件,并且在方法内可以处理传递来的数据
<Student @CustomEventName="getDataFromSonByEmit"></Student> //父组件监听子组件自定义事件
methods: {
getDataFromSonByEmit(param) { //这里的参数param接收的是来自子组件的参数
console.log("来自子组件的数据emit:", param);
this.stuNameEmit = param;
},
},
//子组件
//子组件通过emit触发自定义事件,并且传递出去数据
<button @click="sendDataByEmit">emit方式向父组件传送数据</button>
methods: {
sendDataByEmit() {
this.$emit("CustomEventName", this.studentName); //触发子组件自定义事件并携带参数
},
},以上是普遍使用的emit方法,另外一种就是prop方式:
//父组件
<template>
<div class="school-style">
<h3>来自子组件Prop:{{ stuNameProp }}</h3>
<Student :sonProp="getDataFromSonByProp"></Student> //属性绑定的是方法
</div>
</template>
<script>
import Student from "./Student";
export default {
name: "School",
components: {
Student
},
data() {
return {
studentNameProp: "",
};
},
methods: {
getDataFromSonByProp(param) {
console.log("来自子组件的数据props:", param);
this.studentNameProp = param;
},
},
};
</script>注意子组件的属性sonProp绑定的是一个方法getDataFromSonByProp,这个方法是父组件的方法。一般情况,prop绑定的变量是数组或者对象或者其他任意类型的值。官网文档示例里面并没有提及(Function)方法。这里子组件属性绑定了父组件的方法。
//子组件
<template>
<div class="student-style">
<h2>学生姓名:{{ studentName }}</h2>
<h2>学生年龄:{{ age }}</h2>
<button @click="sendDataByProps">props方式向父组件传送数据</button>
</div>
</template>
<script>
export default {
name: "Student",
data() {
return {
studentName: "张三",
age: 18,
};
},
props: {
sonProp: {
type: Function, //子组件的prop是function类型
},
},
methods: {
sendDataByProps() {
this.sonProp(this.studentName); //这里子组件执行的属性实际执行的是父组件的方法
},
},
};
</script>核心的代码:
//父组件
<Student :sonProp="getDataFromSonByProp"></Student>
data() {
return {
studentNameProp: "",
};
},
methods: {
getDataFromSonByProp(param) {
console.log("来自子组件的数据props:", param);
this.studentNameProp = param; //这里param的值就是来自子组件的studentName
},
},
//子组件
<button @click="sendDataByProps">props方式向父组件传送数据</button>
props: {
sonProp: {
type: Function,
},
},
methods: {
sendDataByProps() {
this.sonProp(this.studentName);//这里相当于执行了父组件的方法getDataFromSonByPro
},
},子组件通过某一个方法触发了prop属性,实际就是父组件的方法,同时把子组件的数据传递到了父组件的方法内,父组件通过自己的响应式状态变量去接收这个数据。





