Vue 动态绑定 Props 详解

作者:犯困乐 发布时间: 2026-05-23 阅读量:9 评论数:0
http://blog.fankunle.cn/archives/019e5248-dc52-7388-8eb4-f9bb228390f5

概述

在 Vue 中,除了静态绑定 props 外,还可以通过 动态绑定 的方式向子组件传递数据。动态绑定允许父组件传递响应式数据、表达式结果等动态变化的值给子组件。

核心概念

动态绑定的语法

动态绑定使用 v-bind 指令或其简写 : 来实现:

<!-- 完整语法 -->
<Child v-bind:prop-name="value" />

<!-- 简写语法 -->
<Child :prop-name="value" />

动态绑定 vs 静态绑定

绑定方式 语法 传递的值 数据类型
静态绑定 num="1" 字符串 "1" String
动态绑定 :num="1" 数字 1 Number

动态绑定支持的数据类型

  • 字符串:name="'张三'"
  • 数字:count="10"
  • 布尔值:disabled="false"
  • 数组:items="[1, 2, 3]"
  • 对象:user="{name: '张三', age: 20}"
  • 表达式:total="count * price"
  • 响应式数据:value="reactiveData"

两种动态绑定对象的方式

方式一:对象属性分别绑定

使用 v-bind="object" 将对象的每个属性分别绑定为子组件的 props。

父组件代码

<template>
  <Child v-bind="bodyInfo" />
</template>

<script setup>
import { reactive } from 'vue'
import Child from './Child.vue'

const bodyInfo = reactive({
  name: 'Mary',
  sex: '女'
})
</script>

等价于

<Child :name="bodyInfo.name" :sex="bodyInfo.sex" />

子组件代码

<template>
  <div>
    <h2>姓名:{{ name }}</h2>
    <h2>性别:{{ sex }}</h2>
  </div>
</template>

<script setup>
const props = defineProps(['name', 'sex'])
</script>

特点

  • 子组件需要分别声明每个属性
  • 对象的属性名必须与子组件的 props 名称匹配
  • 适合对象属性较多且需要单独处理的场景

方式二:传递完整对象

将整个对象作为一个 props 传递给子组件。

父组件代码

<template>
  <Child2 :init="initObj" />
</template>

<script setup>
import Child2 from './Child2.vue'

const initObj = {
  name: '张三',
  sex: '男'
}
</script>

子组件代码

<template>
  <div>
    <h2>姓名:{{ init.name }}</h2>
    <h2>性别:{{ init.sex }}</h2>
  </div>
</template>

<script setup>
const props = defineProps(['init'])
</script>

特点

  • 子组件只需声明一个 props 接收完整对象
  • 通过 props.init.name 的方式访问属性
  • 适合传递复杂对象或配置项

代码实现详解

1. Child.vue(接收多个props)

<template>
  <div>
    <h2>姓名:{{ name }}</h2>
    <h2>性别:{{ sex }}</h2>
  </div>
</template>

<script setup>
const props = defineProps(['name', 'sex'])
</script>

代码解析

  • 使用数组形式声明 props:['name', 'sex']
  • 在模板中直接使用属性名:{{ name }}{{ sex }}

2. Child2.vue(接收完整对象)

<template>
  <div>
    <h2>姓名:{{ init.name }}</h2>
    <h2>性别:{{ init.sex }}</h2>
  </div>
</template>

<script setup>
const props = defineProps(['init'])
</script>

代码解析

  • 只声明一个 props:['init']
  • 在模板中通过点语法访问对象属性:{{ init.name }}

3. Parent.vue(父组件)

<template>
  <div>
    <h3>方式一:对象属性分别绑定</h3>
    <Child v-bind="bodyInfo" />
    
    <h3>方式二:传递完整对象</h3>
    <Child2 :init="initObj" />
  </div>
</template>

<script setup>
import { reactive } from 'vue'
import Child from './Child.vue'
import Child2 from './Child2.vue'

const bodyInfo = reactive({
  name: 'Mary',
  sex: '女'
})

const initObj = {
  name: '张三',
  sex: '男'
}
</script>

代码解析

代码行 说明
第 4 行 使用 v-bind="bodyInfo" 将对象属性展开绑定
第 7 行 使用 :init="initObj" 传递完整对象
第 16-19 行 使用 reactive 创建响应式对象
第 21-24 行 创建普通对象(非响应式)

响应式数据传递

使用 reactive 创建响应式对象

<script setup>
import { reactive } from 'vue'

const bodyInfo = reactive({
  name: 'Mary',
  sex: '女'
})

// 修改数据会自动更新子组件
bodyInfo.name = 'Lucy'
</script>

使用 ref 创建响应式值

<script setup>
import { ref } from 'vue'

const count = ref(0)

// 修改数据
count.value++
</script>

<template>
  <Child :count="count" />
</template>

动态绑定的应用场景

场景一:表单数据传递

<template>
  <FormInput 
    :value="formData.username" 
    :disabled="isSubmitting"
    :placeholder="`请输入${label}`"
  />
</template>

场景二:列表渲染

<template>
  <ul>
    <li v-for="item in list" :key="item.id">
      <ListItem :data="item" :index="$index" />
    </li>
  </ul>
</template>

场景三:条件渲染

<template>
  <div>
    <AdminPanel v-if="isAdmin" :user="currentUser" />
    <UserPanel v-else :user="currentUser" />
  </div>
</template>

注意事项

1. 对象引用传递

当传递对象时,子组件接收到的是对象的引用:

// 父组件
const obj = { name: '张三' }

// 子组件中修改
props.obj.name = '李四'  // 会影响父组件的数据!

解决方案:在子组件中使用浅拷贝或深拷贝

<script setup>
import { ref, reactive, onMounted } from 'vue'

const props = defineProps(['init'])

// 浅拷贝
const localData = { ...props.init }

// 深拷贝(复杂对象)
const deepData = JSON.parse(JSON.stringify(props.init))
</script>

2. 响应式数据更新

使用 reactiveref 创建的数据是响应式的,修改后会自动更新视图。

3. Props 验证

可以为动态绑定的 props 添加类型验证:

<script setup>
const props = defineProps({
  init: {
    type: Object,
    required: true,
    validator(obj) {
      return obj.name && obj.sex
    }
  }
})
</script>

两种绑定方式对比

对比项 方式一:属性分别绑定 方式二:传递完整对象
声明方式 defineProps(['name', 'sex']) defineProps(['init'])
模板使用 {{ name }} {{ init.name }}
数据更新 单个属性更新 整个对象更新
适用场景 属性较少且独立 复杂对象或配置项
灵活性 中等
耦合度 较低 较高

运行效果

页面显示:

方式一:对象属性分别绑定
姓名:Mary
性别:女

方式二:传递完整对象
姓名:张三
性别:男

总结

核心要点

  1. 动态绑定语法:使用 v-bind: 实现
  2. 两种对象绑定方式
    • v-bind="obj":展开对象属性
    • :prop="obj":传递完整对象
  3. 响应式数据:使用 reactiveref 创建
  4. 单向数据流:子组件不应直接修改 props

选择建议

  • 当需要传递多个独立属性时,使用方式一(属性分别绑定)
  • 当需要传递复杂对象或配置时,使用方式二(传递完整对象)
  • 当数据需要响应式更新时,使用 reactive 创建对象

通过动态绑定 props,Vue 实现了灵活的父子组件通信机制,支持传递各种类型的数据,满足不同场景的需求。

演示下载

Child.zip

评论