
概述
在 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. 响应式数据更新
使用 reactive 或 ref 创建的数据是响应式的,修改后会自动更新视图。
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
性别:女
方式二:传递完整对象
姓名:张三
性别:男
总结
核心要点
- 动态绑定语法:使用
v-bind或:实现 - 两种对象绑定方式:
v-bind="obj":展开对象属性:prop="obj":传递完整对象
- 响应式数据:使用
reactive或ref创建 - 单向数据流:子组件不应直接修改 props
选择建议
- 当需要传递多个独立属性时,使用方式一(属性分别绑定)
- 当需要传递复杂对象或配置时,使用方式二(传递完整对象)
- 当数据需要响应式更新时,使用
reactive创建对象
通过动态绑定 props,Vue 实现了灵活的父子组件通信机制,支持传递各种类型的数据,满足不同场景的需求。