Vue2 组件通讯(一):Props传值完全指南

在前几篇文章中,我们学习了组件化开发的基础知识。今天我们来重点攻克Vue组件开发中最重要的内容------组件间的数据通信。本文将详细介绍最常用的Props传值方式,涵盖父传子、子传父以及跨级传递三种场景。

一、组件通信概述

在Vue应用中,组件是独立的存在。为了让组件之间能够协同工作,我们需要一套完善的数据通信机制。

常见的组件关系:

  • 父子关系:最常见的组件关系
  • 兄弟关系:同属于一个父组件的两个子组件
  • 跨级关系:祖孙组件之间的通信

本文重点 :使用 Props​ 实现父子组件和跨级组件的通信。

二、父组件向子组件传递数据(Props)

2.1 核心步骤

父组件向子组件传值分为两步:

  1. 父组件中 :在子组件的标签上使用自定义属性(v-bind)传递数据
  2. 子组件中 :使用 props 选项声明接收父组件传递过来的数据

2.2 代码示例

父组件(App.vue):

复制代码
<template>
    <div id="app">
        <!-- 1. 在子组件标签上绑定数据 -->
        <girl :abc="123" :money1="money" :a="a" />
        <son :car="car" />
    </div>
</template>

<script>
import girl from './components/girl.vue';
import son from './components/son.vue';

export default {
    name: 'App',
    data() {
        return {
            money: 10000,
            car: '宝马',
            a: { b: 666 }
        };
    },
    components: {
        girl,
        son
    }
};
</script>

子组件(girl.vue):

复制代码
<template>
    <div class="girl">
        <h2>girlMsg: {{ girMsg }}</h2>
        <!-- 3. 在模板中像使用data一样使用props -->
        <h3>来自父亲的money: {{ money1 }}</h3>
        <h3>来自父亲的abc: {{ abc }}</h3>
        <h3>来自父组件的b: {{ a.b }}</h3>
    </div>
</template>

<script>
export default {
    name: 'girl',
    data() {
        return {
            girMsg: 'girl组件'
        };
    },
    // 2. 使用props接收数据
    props: ['abc', 'money1', 'a'] // 数组形式(简单声明)
};
</script>

2.3 Props的三种声明方式

方式一:数组形式(简单声明)
复制代码
props: ['abc', 'money1', 'a']

特点:只声明接收哪些属性,不做类型校验。

方式二:对象形式(类型验证)
复制代码
props: {
    abc: String,
    money1: Number
}

特点:指定每个属性的类型,类型不匹配时会在控制台发出警告。

方式三:对象的对象形式(完整验证)
复制代码
props: {
    abc: {
        type: String,       // 类型
        required: true,     // 是否必须传递
        default: '默认值'   // 默认值
    },
    money1: {
        type: Number,
        default: 99         // 默认值
    }
}

完整验证配置项:

配置项 作用 说明
type 指定属性的类型 String, Number, Boolean, Array, Object, Function
required 是否必须传递 true/false
default 默认值 未传递时使用该值
validator 自定义验证函数 返回true表示验证通过

自定义验证示例:

复制代码
props: {
    age: {
        type: Number,
        validator(value) {
            return value >= 0 && value <= 150;
        }
    }
}

2.4 重要注意事项

⚠️ 单向数据流

子组件不应直接修改props。修改会触发警告,且父组件的数据不会更新。

复制代码
// ❌ 错误:直接修改props
this.money1 = 20000; // 会报警告

为什么要有单向数据流?

  • 防止子组件意外修改父组件的状态
  • 保证数据流向清晰,便于调试和维护
⚠️ 复杂数据类型(对象、数组)

修改内部属性 :Vue可以检测到,但不推荐这样做,因为它破坏了数据流的清晰性。

复制代码
// 可以修改,但不推荐
this.a.b = 999; // Vue能检测到变化

直接替换整个对象:Vue检测不到,且会报错。

复制代码
// ❌ 错误:直接替换整个对象
this.a = { b: 888 }; // Vue检测不到,会报错

正确做法:如果需要修改,应该在父组件中进行。

三、子组件向父组件传递数据(自定义事件)

3.1 核心步骤

子组件向父组件传值分为三步:

  1. 父组件中:定义一个方法,用于接收数据和处理逻辑
  2. 父组件中 :将这个方法通过props传递给子组件
  3. 子组件中:通过props接收父组件传过来的函数,在需要传递数据时调用该函数并将数据作为参数传入

3.2 代码示例

父组件(App.vue):

复制代码
<template>
    <div id="app">
        <h1>app组件</h1>
        <h3>来自girl组件的孝敬:{{ girlMoney }}</h3>
        <div class="box">
            <!-- 2. 将方法传递给子组件 -->
            <girl :getGirlMoney="getGirlMoney" />
        </div>
    </div>
</template>

<script>
import girl from './components/girl.vue';

export default {
    name: 'App',
    data() {
        return {
            girlMoney: 0
        };
    },
    components: { girl },
    methods: {
        // 1. 父组件定义方法,val形参用于接收子组件数据
        getGirlMoney(val) {
            this.girlMoney = val; // 3. 用子组件传来的数据更新自身状态
        }
    }
};
</script>

子组件(girl.vue):

复制代码
<template>
    <div class="girl">
        <h2>girlMsg: {{ girlMsg }}</h2>
        <h3>girlMoney: {{ girlMoney }}</h3>
        <!-- 4. 触发事件:调用父组件传过来的函数,并传递数据 -->
        <button @click="getGirlMoney(girlMoney)">点击传递grilMoney</button>
    </div>
</template>

<script>
export default {
    name: 'girl',
    data() {
        return {
            girMsg: 'girl组件',
            girlMoney: 500
        };
    },
    // 3. 子组件接收父组件传递的函数
    props: ['getGirlMoney']
};
</script>

3.3 执行流程

复制代码
用户点击按钮
    ↓
调用 getGirlMoney(girlMoney)
    ↓
getGirlMoney 是父组件传过来的函数
    ↓
执行父组件中的 getGirlMoney(val) 方法
    ↓
val = 500(子组件的 girlMoney)
    ↓
this.girlMoney = 500(更新父组件数据)
    ↓
页面更新显示:来自girl组件的孝敬:500

四、跨级组件通信(Props逐级传递)

4.1 概念

如果爷爷组件(App)需要向孙组件(child)传递数据,而中间隔着一个父组件(son),可以通过props逐级传递。

复制代码
App(爷爷) → son(父亲) → child(孙子)

4.2 代码示例

爷爷组件(App.vue):

复制代码
<template>
    <div id="app">
        <!-- 将car传递给son组件 -->
        <son :car="car" />
    </div>
</template>

<script>
import son from './components/son.vue';

export default {
    name: 'App',
    data() {
        return {
            car: '宝马'
        };
    },
    components: { son }
};
</script>

父组件(son.vue):

复制代码
<template>
    <div class="son">
        <h2>sonMsg: {{ sonMsg }}</h2>
        <h3>来自父亲的car: {{ car }}</h3>
        <!-- 接收App的car,并继续向下传递给child组件 -->
        <child :car="car" />
    </div>
</template>

<script>
import child from './child.vue';

export default {
    name: 'son',
    props: ['car'], // 接收来自App的数据
    components: { child }
};
</script>

孙组件(child.vue):

复制代码
<template>
    <div class="child">
        <h3>childMsg: {{ childMsg }}</h3>
        <!-- 最终使用从son传递过来的car -->
        <h4>来自爷爷的car: {{ car }}</h4>
    </div>
</template>

<script>
export default {
    name: 'child',
    props: ['car'] // 接收来自son的数据
};
</script>

4.3 逐级传递的局限性

问题 说明
繁琐​ 如果组件层级很深,逐级传递会非常麻烦
冗余​ 中间组件即使不使用该数据,也需要接收并转发
难维护​ 修改数据结构时需要改动所有中间组件

解决方案:

  • 简单的跨级传递:可以使用 provide / inject
  • 复杂的跨级或兄弟组件通信:使用 Vuex 状态管理库

这些内容将在后续文章中详细讲解。

五、总结

5.1 通信方式对比

通信方式 方向 核心API 适用场景
Props 父→子 v-bind + props 最常见的数据传递方式
自定义事件 子→父 父传函数,子调用 子组件通知父组件状态变化
逐级传递 祖先→后代 多层props 简单的跨级传递,层级不深时
provide/inject 祖先→后代 provide + inject 深层级的跨级传递
Vuex 任意 状态管理 复杂的跨级或兄弟组件通信

5.2 Props最佳实践

场景 推荐做法
简单传值 数组形式声明props
需要类型校验 对象形式声明props
需要默认值或必填 完整验证形式
修改props ❌ 不要直接修改,通过父组件修改
复杂类型内部属性 可以修改但不推荐
子传父 使用函数类型的props

5.3 注意事项清单

  • ✅ Props遵循单向数据流原则
  • ✅ 子组件不要直接修改props
  • ✅ 复杂类型(对象/数组)谨慎操作
  • ✅ 使用类型验证增强代码健壮性
  • ✅ 跨级传递过多时考虑其他方案

掌握了Props传值,你已经可以应对大部分组件通信场景。下一篇文章我们将继续学习 $emit 事件派发和更高级的通信方式,敬请期待!

相关推荐
卸任5 小时前
Vibe coding工具使用心得
前端·ai编程
brien96 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance6 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M6 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写6 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李6 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易7 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
清晨Coding7 小时前
删了 Cookie 还能自动登录?Google系网站登录态自动恢复的原理分析
javascript
风骏时光牛马7 小时前
前沿视界
前端
kyriewen7 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员