×

Vue 父子组件通信:Props 介绍

独孤求败 独孤求败 发表于2026-06-09 10:15:28 浏览12 评论0

抢沙发发表评论

Vue 中可以创建和复用组件。每个组件都有自己独立的状态、逻辑和生命周期,可以看作一个相对独立的功能单元。在组件树中,如果一个组件在模板中使用了另一个组件,那么使用者称为父组件(Parent Component),被使用者称为子组件(Child Component)。

在实际开发中,父子组件之间经常需要进行通信和数据传递。那么,Vue 中的父子组件该如何传值呢?

Vue 为父子组件之间的通信提供了多种方式。其中,最常用的方式就是通过 Props 由父组件向子组件传递数据。

Props定义

子组件如果想要从外部接受数据,需要主动声明

  const ChildComponent = {
        // 省略...
        props: ['msg'// 声明接收一个名叫 msg 的属性
    };

子组件通过 Props 声明了自己需要接收哪些数据,那么父组件该如何向子组件传递这些数据呢?

父组件向子组件传递数据有两种方式:静态传值和动态传值。无论采用哪种方式,父组件传递的属性名都需要与子组件声明的 Props 名称保持一致。

所谓静态传值,其实就是写死的值,不可变的,直接将固定的值写在组件标签的属性上,用于向子组件传递数据。

<!--浏览器环境大小写不敏感,所系需要用下面这种方式引入驼峰的子组件-->
<child-component msg="Hello World"></child-component>

动态传值需要借助 v-bind 指令,它可以将父组件中的变量或响应式数据绑定到子组件的 Props 上。

下例中的:msgv-bind指令的缩写。

<child-component :msg="text"></child-component>
<script>
   
    // 【父组件/根应用】
    Vue.createApp({
          
        data() {
            return {
                text'Hello World' 
            }
        }
    }).mount('#root');
</script>

下面来看一个 Props 动态传值的完整示例。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue 3 极简传值</title>
    <script src="https://unpkg.com/vue@3.5.17/dist/vue.global.js"></script>
</head>
<body>
    <div id="root"></div>

    <template id="parent-box">
        <div>
            <h2>我是父组件</h2>
            <child-component :msg="text"></child-component>
        </div>
    </template>

    <template id="child-box">
        <div>
            <h3>我是子组件</h3>
            <p>父组件传给我的内容是:{{ msg }}</p>
        </div>
    </template>
</body>

<script>
    // 【子组件配置】
    constChildComponent = {
        template'#child-box',
        props: ['msg'// 声明接收一个名叫 msg 的属性
    };

    // 【父组件/根应用】
    Vue.createApp({
        template'#parent-box',
        components: {
            'child-component'ChildComponent// 注册子组件
        },
        data() {
            return {
                text'Hello World'// 父组件里的数据
            }
        }
    }).mount('#root');
</script>
</html>

单向数据流

Props 采用单向数据流设计,数据只能从父组件流向子组件。当父组件更新传递给 Props 的数据时,子组件会同步接收到最新的值。子组件不能直接修改 Props 的值,即使尝试修改,也不会真正改变父组件中的数据,并且 Vue 会在开发环境下给出警告。

下面的这个运行后会收到到警告。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue 3 极简传值</title>
    <script src="https://unpkg.com/vue@3.5.17/dist/vue.global.js"></script>
</head>
<body>
    <div id="root"></div>

    <template id="parent-box">
        <div>
            <h2>我是父组件</h2>
            <child-component :msg="text"></child-component>
        </div>
    </template>

    <template id="child-box">
        <div>
            <h3>我是子组件</h3>
            <p>父组件传给我的内容是:{{ msg }}</p>
        </div>
    </template>
</body>

<script>
    // 【子组件配置】
    constChildComponent = {
        template'#child-box',
        props: ['msg'],// 声明接收一个名叫 msg 的属性
        mounted() {
            this.msg = "子组件修改了父组件传来的值"// 试图修改父组件传来的值
        }
    };

    // 【父组件/根应用】
    Vue.createApp({
        template'#parent-box',
        components: {
            'child-component'ChildComponent// 注册子组件
        },
        data() {
            return {
                text'Hello World'// 父组件里的数据
            }
        }
    }).mount('#root');
</script>
</html>

图片

Props校验

虽然 Props 具有单向数据流的特性,但这并不意味着子组件会无条件地接收父组件传递的数据。

Vue 提供了完善的 Props 校验机制,开发者可以在子组件中对接收到的数据进行约束和验证,例如限制数据类型、设置默认值以及标记某个 Props 是否为必填项等。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue 3 极简传值</title>
    <script src="https://unpkg.com/vue@3.5.17/dist/vue.global.js"></script>
</head>
<body>
    <div id="root"></div>

    <template id="parent-box">
        <div>
            <h2>我是父组件</h2>
            <child-component :msg="text"></child-component>
        </div>
    </template>

    <template id="child-box">
        <div>
            <h3>我是子组件</h3>
            <p>父组件传给我的内容是:{{ msg }}</p>
        </div>
    </template>
</body>

<script>
    // 【子组件配置】
    constChildComponent = {
        template'#child-box',
        props: {
            msg: {
                 typeString,
                 requiredfalse,
                 default"Hello World",
                 validatorfunction(value) {
                        return value == 'Hello World';
                 }
            }
           
        }
    };

    // 【父组件/根应用】
    Vue.createApp({
        template'#parent-box',
        components: {
            'child-component'ChildComponent// 注册子组件
        },
        data() {
            return {
                text'Hello World!'// 父组件里的数据
            }
        }
    }).mount('#root');
</script>
</html>

从这个例子中可以看到,Vue 为 Props 提供了丰富的校验选项:

  • • type:用于校验 Props 的数据类型。
  • • required:用于指定该 Props 是否为必传项。
  • • default:用于设置默认值,当父组件未传递该 Props 时,将使用这里定义的默认值。
  • validator:用于自定义校验规则。它接收当前 Props 的值作为参数,并返回一个布尔值,true 表示校验通过,false 表示校验失败。
  • 以上只是 Props 校验的常见用法,更多高级配置请参考官方文档。

    https://cn.vuejs.org/guide/components/props#prop-validation

注意:Props 校验并不是强制性的。 当父组件传递的数据不符合子组件定义的规则时,Vue 只会在控制台输出警告信息,而不会阻止组件继续渲染。

换句话说,Props 校验的主要目的是帮助开发者在开发阶段尽早发现问题,而不是在运行时强制中断程序的执行。

图片

优雅的对象传参

Props 不仅支持字符串、数字、布尔值等基本数据类型,还支持对象、数组等复杂数据类型。

当需要向子组件传递多组相关数据时,与其定义多个 Props,不如将它们封装成一个对象统一传递,这样代码会更加简洁、易于维护。

下面通过一个示例来演示如何使用 Props 传递对象数据。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue3传递对象属性示例</title>
    <script src="https://unpkg.com/vue@3.5.17/dist/vue.global.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color#f5f5f5;
            padding20px;
        }
        .container {
            max-width600px;
            margin0 auto;
        }
        /* 子组件卡片样式 */
        .card {
            background: white;
            padding20px;
            border-radius8px;
            box-shadow04px6pxrgba(0,0,0,0.1);
            margin-bottom20px;
        }
        .cardh2 {
            margin-top0;
            color#333;
        }
        .cardp {
            color#666;
            margin5px0;
        }
        .highlight {
            color#42b983;
            font-weight: bold;
        }
    
</style>
</head>
<body>

    <div id="root" class="container">
        <h2>父组件区域</h2>
        <p>当前父组件中的数据对象 <code>userProfile</code> 包含 4 个属性。</p>
        <hr>
        
        <h2>子组件展示区域</h2>
        <user-card :user-profile="userProfile"></user-card>
    </div>

    <script>
        // 1. 创建父组件
        const app = Vue.createApp({
            data() {
                return {
                    // 定义一个包含多个属性的对象
                    userProfile: {
                        name: '打工人小张',
                        age: 26,
                        role: '高级全栈开发工程师',
                        city: '北京'
                    }
                }
            }
        });

        // 2. 注册子组件 'user-card'
        app.component('user-card', {
            // 子组件正常声明它需要接收的单项属性
            props: ['userProfile'], 
            
            // 在模板中直接像普通 prop 一样使用它们
            template: `
                <div class="card">
                    <h3>👤 用户信息卡片 (子组件)</h3>
                    <p><strong>姓名:</strong> <span class="highlight">
{{ userProfile.name }}</span></p>
                    <p><strong>年龄:</strong> 
{{ userProfile.age }} 岁</p>
                    <p><strong>职位:</strong> 
{{ userProfile.role }}</p>
                    <p><strong>城市:</strong> 
{{ userProfile.city }}</p>
                </div>
            `
        });

        // 3. 挂载到页面上
        app.mount('#root');
    
</script>

</body>
</html>

本例通过 Props 传递了一个 userProfile 对象。相比逐个传递多个属性,将相关数据封装成对象统一传递更加简洁、易维护。子组件只需声明一个 Props,即可访问对象中的所有字段。同时需要牢记,Props 中的对象同样遵循单向数据流原则,子组件负责读取和展示数据,而不应直接修改数据内容。

这里还有一种简写形式。通过 v-bind 直接绑定一个对象,Vue 会自动展开对象中的所有属性,子组件只需声明自己需要的 Props 即可。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue3 v-bind 批量绑定对象属性示例</title>
    <script src="https://unpkg.com/vue@3.5.17/dist/vue.global.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color#f5f5f5;
            padding20px;
        }
        .container {
            max-width600px;
            margin0 auto;
        }
        /* 子组件卡片样式 */
        .card {
            background: white;
            padding20px;
            border-radius8px;
            box-shadow04px6pxrgba(0,0,0,0.1);
            margin-bottom20px;
        }
        .cardh2 {
            margin-top0;
            color#333;
        }
        .cardp {
            color#666;
            margin5px0;
        }
        .highlight {
            color#42b983;
            font-weight: bold;
        }
    
</style>
</head>
<body>

    <div id="root" class="container">
        <h2>父组件区域</h2>
        <p>当前父组件中的数据对象 <code>userProfile</code> 包含 4 个属性。</p>
        <hr>
        
        <h2>子组件展示区域</h2>
        <user-card v-bind="userProfile"></user-card>
    </div>

    <script>
        // 1. 创建父组件
        const app = Vue.createApp({
            data() {
                return {
                    // 定义一个包含多个属性的对象
                    userProfile: {
                        name: '打工人小张',
                        age: 26,
                        role: '高级全栈开发工程师',
                        city: '北京'
                    }
                }
            }
        });

        // 2. 注册子组件 'user-card'
        app.component('user-card', {
            // 子组件正常声明它需要接收的单项属性
            props: ['name', 'age', 'role', 'city'],
            
            // 在模板中直接像普通 prop 一样使用它们
            template: `
                <div class="card">
                    <h3>👤 用户信息卡片 (子组件)</h3>
                    <p><strong>姓名:</strong> <span class="highlight">
{{ name }}</span></p>
                    <p><strong>年龄:</strong> 
{{ age }} 岁</p>
                    <p><strong>职位:</strong> 
{{ role }}</p>
                    <p><strong>城市:</strong> 
{{ city }}</p>
                </div>
            `
        });

        // 3. 挂载到页面上
        app.mount('#root');
    
</script>

</body>
</html>


 

在这个例子中,父组件使用了 v-bind="userProfile" 的写法,将整个对象一次性传递给子组件。Vue 会自动将对象中的每个属性展开,并将其作为独立的 Props 进行传递。

在子组件中,我们不再需要声明一个 userProfile 对象,而是可以根据实际需求按需声明所需的 Props,例如 nameagerole 和 city
这种写法能够减少重复代码,使模板更加简洁。当对象中包含大量属性时,使

用 v-bind 对象展开语法往往比逐个绑定 Props 更加优雅和高效。

不过需要注意的是,子组件声明的 Props 名称必须与对象中的属性名保持一致,否则对应的数据将无法正确接收。

 

两种方式如何选择?

一般来说,如果子组件需要整体操作一个对象,可以直接传递对象;如果子组件只关心对象中的部分字段,那么使用 v-bind 对象展开语法会更加灵活。这样既能保持组件接口清晰,又能降低父组件编写模板时的复杂度。


群贤毕至

访客