组件是 Vue.js 最强大的功能之一,但组件实例的作用域相互独立,不同组件之间无法直接引用数据。因此,实现父子组件间的通信成为 Vue 开发中的关键技能。本文通过 props、$ref 和 $emit 三个核心 API,结合实际代码示例,讲解父组件向子组件、子组件向父组件传递数据的几种方式。
在开始之前,先建立两个基础组件:father.vue 和 child.vue。
- <!-- 父组件 father.vue -->
- <template>
- <div>
- <h1>我是父组件!</h1>
- <child></child>
- </div>
- </template>
- <script>
- import Child from '../components/child.vue'
- export default {
- components: { Child }
- }
- </script>
复制代码- <!-- 子组件 child.vue -->
- <template>
- <h3>我是子组件!</h3>
- </template>
- <script>
- export default {
- }
- </script>
复制代码
父组件通过 import 导入子组件,并在 components 中注册,随后即可在模板中以 <child> 标签的形式嵌入子组件。
一、通过 props 实现父传子
子组件的 props 选项用于接收父组件传递的数据。props 是单向绑定的:只能父组件向子组件传递,不可反向。传递方式分为静态传递和动态传递。
1. 静态传递
子组件在 export default 中声明 props 数组或对象,父组件在子组件标签上通过自定义属性传递静态字符串。
- <!-- 父组件 -->
- <template>
- <div>
- <h1>我是父组件!</h1>
- <child message="我是子组件一!"></child>
- </div>
- </template>
- <script>
- import Child from '../components/child.vue'
- export default {
- components: { Child }
- }
- </script>
复制代码- <!-- 子组件 -->
- <template>
- <h3>{{ message }}</h3>
- </template>
- <script>
- export default {
- props: ['message']
- }
- </script>
复制代码
2. 动态传递
多数场景需要传递动态数据(表达式、变量、布尔值、对象等)。使用 v-bind 将属性绑定到父组件的数据或 JavaScript 表达式。
- <!-- 父组件 -->
- <template>
- <div>
- <h1>我是父组件!</h1>
- <child v-bind:message="a + b"></child>
- <child v-bind:message="msg"></child>
- </div>
- </template>
- <script>
- import Child from '../components/child.vue'
- export default {
- components: { Child },
- data() {
- return {
- a: '我是子组件二!',
- b: 112233,
- msg: '我是子组件三!' + Math.random()
- }
- }
- }
- </script>
复制代码
子组件接收方式与静态传递相同。
二、通过 $ref 实现父调用子方法和属性
ref 被用来给元素或子组件注册引用信息,引用信息会注册在父组件的 $refs 对象上。若 ref 用于子组件,则指向子组件实例,父组件可通过 this.$refs.refName 访问子组件中定义的属性和方法;若 ref 用于普通 DOM 元素,则指向该元素,作用类似 jQuery 选择器。
下面用 $ref 实现父组件向子组件传递数据(通过调用子组件方法):
- <!-- 父组件 -->
- <template>
- <div>
- <h1>我是父组件!</h1>
- <child ref="msg"></child>
- </div>
- </template>
- <script>
- import Child from '../components/child.vue'
- export default {
- components: { Child },
- mounted() {
- console.log(this.$refs.msg);
- this.$refs.msg.getMessage('我是子组件一!');
- }
- }
- </script>
复制代码- <!-- 子组件 -->
- <template>
- <h3>{{ message }}</h3>
- </template>
- <script>
- export default {
- data() {
- return {
- message: ''
- }
- },
- methods: {
- getMessage(m) {
- this.message = m;
- }
- }
- }
- </script>
复制代码
在父组件 mounted 钩子中,通过 this.$refs.msg.getMessage('...') 调用子组件方法,将参数传入子组件。
props 与 $ref 的区别:
- props 侧重于数据传递,不能调用子组件的属性和方法,适合静态或动态数据绑定(如文章组件自定义标题和内容)。
- $ref 侧重于索引,主要用于调用子组件内部的属性和方法,不擅长数据传递。ref 在 DOM 元素上使用时,还能起到选择器的作用,该功能比作为组件索引更常用。
三、通过 $emit 实现子传父
$emit 用于子组件向父组件通信。语法:vm.$emit(event, arg) —— 绑定一个自定义事件 event,当执行该语句时,会将参数 arg 传递给父组件。父组件通过 @event 监听并接收参数。
- <!-- 父组件 -->
- <template>
- <div>
- <h1>{{ title }}</h1>
- <child @getMessage="showMsg"></child>
- </div>
- </template>
- <script>
- import Child from '../components/child.vue'
- export default {
- components: { Child },
- data() {
- return {
- title: ''
- }
- },
- methods: {
- showMsg(title) {
- this.title = title;
- }
- }
- }
- </script>
复制代码- <!-- 子组件 -->
- <template>
- <h3>我是子组件!</h3>
- </template>
- <script>
- export default {
- mounted() {
- this.$emit('getMessage', '我是父组件!');
- }
- }
- </script>
复制代码
子组件在 mounted 生命周期中触发 $emit,发出 'getMessage' 事件,并传递字符串。父组件监听该事件,触发 showMsg 方法,更新 title 数据。
以上就是 Vue 父子组件间三种主要通信方式的实践总结。掌握 props、$ref、$emit 的原理和使用场景,即可轻松应对大多数组件交互需求。 |