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 事件派发和更高级的通信方式,敬请期待!

相关推荐
码艺-Alimjan1 小时前
Tauri 2.x + Vue 3 桌面应用开发实战:从踩坑到完美落地
前端·javascript·vue.js·rust·typescript·go
qq_570398571 小时前
Three.js基础使用-案例
开发语言·javascript·ecmascript
AINative软件工程1 小时前
编程
前端·llm
晴天161 小时前
peerDependencies 全面解析:前端依赖生态的核心机制与实战指南
前端·npm
I'mChloe1 小时前
群晖部署 image-matting:把人像去背景做成一个随开随用的 Web 工具
android·前端
程序员蜡笔熊1 小时前
Vite 8 换芯实测:Rolldown 替掉双引擎,构建快 3.19 倍
前端·javascript·vue
右耳朵猫AI1 小时前
Web前端周刊2026W36 | pnpm 12 Rust 重写、Remix 3 RC、Node.js 26.8.0、htmx 4.0 大版本
前端·rust·node.js
平头哥~2 小时前
Day 21 | animation 与 keyframes:把动画从 A 到 B 变成多点编排
前端·css·css3·css学习
宿67411 小时前
vue3-包管理器
前端·vue.js