Vue 3 静态与动态 Props 如何传递?TypeScript 类型约束有何必要?

一、Props 基础概念

Props 是 Vue 3 中实现组件间通信的核心机制之一,允许父组件向子组件传递数据。它遵循单向数据流原则,即数据只能从父组件流向子组件,子组件不能直接修改父组件传递的 Props,确保了数据流向的清晰可预测。

二、静态 Props 的传递方法

静态 Props 是指传递给子组件的固定值,不会随父组件数据变化而改变。

2.1 基本用法

在父组件中直接通过属性名传递固定值:

vue 复制代码
<!-- 父组件 Parent.vue -->
<template>
  <ChildComponent title="欢迎来到 Vue 3 世界" />
</template>

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

子组件通过 defineProps 接收:

vue 复制代码
<!-- 子组件 ChildComponent.vue -->
<template>
  <h1>{{ title }}</h1>
</template>

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

2.2 静态 Props 的特点

  • 传递的值是固定的字符串或基本类型
  • 不需要使用 v-bind 指令
  • 适用于传递不会变化的配置信息

三、动态 Props 的传递方法

动态 Props 允许我们将父组件的响应式数据传递给子组件,当父组件数据变化时,子组件会自动更新。

3.1 基本用法

使用 v-bind 指令(或简写 :)绑定父组件的数据:

vue 复制代码
<!-- 父组件 Parent.vue -->
<template>
  <ChildComponent :message="parentMessage" :count="parentCount" />
  <button @click="parentCount++">增加计数</button>
</template>

<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'

const parentMessage = ref('这是动态传递的消息')
const parentCount = ref(0)
</script>

子组件接收并使用:

vue 复制代码
<!-- 子组件 ChildComponent.vue -->
<template>
  <p>{{ message }}</p>
  <p>当前计数:{{ count }}</p>
</template>

<script setup>
const props = defineProps(['message', 'count'])
</script>

3.2 动态 Props 的高级用法

3.2.1 传递对象

可以一次性传递多个属性:

vue 复制代码
<!-- 父组件 -->
<template>
  <ChildComponent :user="userInfo" />
</template>

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

const userInfo = reactive({
  name: '张三',
  age: 25,
  email: 'zhangsan@example.com'
})
</script>

子组件接收:

vue 复制代码
<!-- 子组件 -->
<template>
  <div>
    <p>姓名:{{ user.name }}</p>
    <p>年龄:{{ user.age }}</p>
    <p>邮箱:{{ user.email }}</p>
  </div>
</template>

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

3.2.2 传递数组

vue 复制代码
<!-- 父组件 -->
<template>
  <ChildComponent :items="list" />
</template>

<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'

const list = ref(['Vue', 'React', 'Angular'])
</script>

往期文章归档

子组件接收并渲染:

vue 复制代码
<!-- 子组件 -->
<template>
  <ul>
    <li v-for="item in items" :key="item">{{ item }}</li>
  </ul>
</template>

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

3.3 动态 Props 流程图

markdown 复制代码
父组件响应式数据变化
    ↓
v-bind 自动更新传递给子组件的 Props
    ↓
子组件接收到更新后的 Props
    ↓
子组件模板自动重新渲染

四、TypeScript 类型约束

在 Vue 3 中使用 TypeScript 可以为 Props 添加严格的类型约束,提高代码的可维护性和可靠性。

4.1 使用接口定义 Props 类型

vue 复制代码
<!-- 子组件 ChildComponent.vue -->
<template>
  <div>
    <p>标题:{{ title }}</p>
    <p>计数:{{ count }}</p>
    <p>用户信息:{{ user.name }} - {{ user.age }}</p>
  </div>
</template>

<script setup lang="ts">
interface User {
  name: string
  age: number
}

interface Props {
  title: string
  count: number
  user: User
  // 可选属性
  description?: string
}

const props = defineProps<Props>()
</script>

4.2 为 Props 添加默认值

使用 withDefaults 函数为 Props 设置默认值:

vue 复制代码
<script setup lang="ts">
interface User {
  name: string
  age: number
}

interface Props {
  title: string
  count: number
  user: User
  description?: string
}

const props = withDefaults(defineProps<Props>(), {
  title: '默认标题',
  count: 0,
  user: () => ({
    name: '默认用户',
    age: 18
  }),
  description: '这是一个默认描述'
})
</script>

4.3 类型约束的优势

  • 编译时类型检查,提前发现错误
  • 更好的 IDE 自动补全和类型提示
  • 清晰的组件 API 文档
  • 减少运行时错误

五、课后 Quiz

问题 1:如何区分静态 Props 和动态 Props?它们的使用场景有什么不同?

答案解析:

  • 静态 Props 直接传递固定值,不需要使用 v-bind,适用于传递不会变化的配置信息,如组件标题、静态文本等。
  • 动态 Props 使用 v-bind 绑定父组件的响应式数据,当父组件数据变化时,子组件会自动更新,适用于需要动态展示的数据,如列表数据、用户信息等。

问题 2:在 Vue 3 + TypeScript 项目中,如何为 Props 定义类型并设置默认值?

答案解析:

  1. 首先定义接口来描述 Props 的类型:
typescript 复制代码
interface Props {
  title: string
  count: number
  description?: string
}
  1. 使用 withDefaults 函数结合 defineProps 来设置默认值:
typescript 复制代码
const props = withDefaults(defineProps<Props>(), {
  title: '默认标题',
  count: 0,
  description: '默认描述'
})

六、常见报错解决方案

错误 1:[Vue warn]: Missing required prop: "title"

原因分析: 子组件声明了必填的 Props,但父组件没有传递。 解决办法:

  1. 父组件中传递对应的 Props:
vue 复制代码
<ChildComponent title="我是必填标题" />
  1. 或者在子组件中将该 Props 设置为可选:
typescript 复制代码
interface Props {
  title?: string
}

错误 2:[Vue warn]: Invalid prop: type check failed for prop "count". Expected Number, got String with value "10".

原因分析: 传递的 Props 类型与子组件声明的类型不匹配。 解决办法:

  1. 确保传递的值类型正确,使用 v-bind 传递数字类型:
vue 复制代码
<ChildComponent :count="10" />
  1. 或者在子组件中调整类型定义:
typescript 复制代码
interface Props {
  count: number | string
}

错误 3:Cannot assign to read only property 'title' of object '#<Object>'

原因分析: 子组件尝试直接修改父组件传递的 Props,违反了单向数据流原则。 解决办法:

  1. 如果需要修改数据,应该在子组件中定义本地响应式数据,将 Props 作为初始值:
typescript 复制代码
const props = defineProps<{ title: string }>()
const localTitle = ref(props.title)
  1. 或者通过触发父组件的方法来修改数据:
vue 复制代码
<!-- 子组件 -->
<button @click="$emit('update:title', '新标题')">修改标题</button>
vue 复制代码
<!-- 父组件 -->
<ChildComponent :title="parentTitle" @update:title="parentTitle = $event" />
相关推荐
未秃头的程序猿1 小时前
深入浅出MySQL事务:从ACID到Spring失效场景,2026最新实战指南
java·后端
程序员库里1 小时前
TipTap简介
前端·javascript·面试
关中老四1 小时前
【js/web甘特图插件MZGantt】如何使用外部弹框添加和修改任务(updRows方法使用说明)
前端·javascript·甘特图·甘特图插件
ponponon1 小时前
openclaw 打开 gui web 页面遇到 token 失效的问题原因和解决方案
后端
nunumaymax2 小时前
css实现元素和文字从右向左排列
前端·css
fengxin_rou2 小时前
黑马点评实战篇|第五篇:分布式锁-redission
java·数据库·redis·后端·缓存
tsyjjOvO2 小时前
Spring 核心知识点全解析(续)
java·后端·spring
旷世奇才李先生2 小时前
043校园二手交易平台系统-springboot+vue
java·vue.js·spring boot