chaihongjun.me

Vue2中子组件向父组件传值的两种方式prop和emit

在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属性,实际就是父组件的方法,同时把子组件的数据传递到了父组件的方法内,父组件通过自己的响应式状态变量去接收这个数据。

知识共享许可协议本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。作者:柴宏俊»