Vue3核心语法进阶(Props)

发布于:2025-08-06 ⋅ 阅读:(14) ⋅ 点赞:(0)

 Vue3 中的 Props:父子组件的“传话筒”详解

接下来我们来聊聊 Vue3 中一个超级基础但又极其重要的概念——Props

如果你已经会用 Vue 写组件,那你一定用过 props。但你真的完全理解它吗?比如:

  • 为什么子组件不能直接改 props?
  • 什么时候该用 .sync 或 v-model
  • 如何给 props 加类型验证和默认值?

别急!今天我就用比喻,带你彻底搞懂 Vue3 的 Props,让你从“会用”变成“精通”!


什么是 Props?(一句话说清)

Props 就是父组件传给子组件的数据,相当于“父子之间的传话筒”。

想象一下:你爸(父组件)想让你(子组件)去超市买牛奶,他会告诉你:

  • 买什么?—— 牛奶
  • 买几瓶?—— 2 瓶
  • 什么牌子?—— 蒙牛

这些信息,就是 Props

<!-- 父组件 App.vue -->
<template>
  <BuyMilk 
    item="牛奶" 
    count="2" 
    brand="蒙牛" 
  />
</template>
<!-- 子组件 BuyMilk.vue -->
<script setup>
// 接收父组件传来的数据
defineProps(['item', 'count', 'brand'])
</script>

<template>
  <div>我要去买 {{ count }} 瓶 {{ brand }} {{ item }}!</div>
</template>

输出结果:我要去买 2 瓶 蒙牛 牛奶!

这就是 Props 的最基本用法:父传子,单向数据流


如何在 Vue3 中定义 Props?

Vue3 推荐使用 <script setup> + defineProps(),它是一个编译宏(不需要引入),写起来超简单!

方式一:数组写法(简单场景)

defineProps(['title', 'content', 'author'])

适合快速原型,但不推荐生产环境用,因为没类型、没默认值。

方式二:对象写法(推荐!)

defineProps({
  title: String,
  content: String,
  author: {
    type: String,
    default: '匿名用户'
  },
  likes: {
    type: Number,
    default: 0
  },
  isActive: {
    type: Boolean,
    default: true
  }
})

 这才是专业写法!支持类型、默认值、必填校验等。


讲解:Props 的“只读性”(为什么不能改?)

这是新手最容易踩的坑!

错误示范:

const props = defineProps(['count'])

// 想要增加数量?
props.count++ //  警告!不要直接修改 props!

为什么不能改?

因为 Props 是“只读”的,就像你爸告诉你“买 2 瓶牛奶”,你不能偷偷改成“买 3 瓶”然后说“爸说的”!

Vue 的设计哲学是:数据流向要清晰。父组件传数据,子组件只能用,不能私自篡改。


那我想改怎么办?—— 用 emit 反向通知!

正确的做法是:子组件通过 emit 告诉父组件:“我想改数据”,然后由父组件决定是否修改。

示例:一个可增减的计数器

<!-- 子组件 Counter.vue -->
<script setup>
const props = defineProps(['count'])
const emit = defineEmits(['update:count'])

const increase = () => {
  emit('update:count', props.count + 1)
}

const decrease = () => {
  emit('update:count', props.count - 1)
}
</script>

<template>
  <div>
    <button @click="decrease">-</button>
    {{ count }}
    <button @click="increase">+</button>
  </div>
</template>
<!-- 父组件 App.vue -->
<script setup>
import { ref } from 'vue'
import Counter from './Counter.vue'

const myCount = ref(5)
</script>

<template>
  <Counter 
    :count="myCount" 
    @update:count="myCount = $event"
  />
</template>

看到了吗?子组件不能自己改,但可以“申请修改”,父组件同意了才算数!


语法糖:v-model 和 .sync 的秘密

上面的 @update:count 写起来有点啰嗦?Vue 提供了语法糖!

方式一:用 v-model(最常用)

<!-- 父组件 -->
<Counter v-model="myCount" />

<!-- 等价于 -->
<Counter 
  :count="myCount" 
  @update:count="myCount = $event"
/>

注意:默认 v-model 对应的是 modelValueupdate:modelValue

如果你想用别的名字,比如 v-model:count

<!-- 子组件 -->
defineProps(['count'])
defineEmits(['update:count'])

<!-- 父组件 -->
<Counter v-model:count="myCount" />

方式二:.sync 修饰符(Vue2 遗留,Vue3 仍支持)

<!-- 父组件 -->
<Counter :count.sync="myCount" />

<!-- 等价于 -->
<Counter 
  :count="myCount" 
  @update:count="myCount = $event"
/>

推荐用 v-model,更现代、更清晰。


Props 高级用法:类型、默认值、验证

1. 支持复杂类型

defineProps({
  userInfo: {
    type: Object,
    default: () => ({ name: '张三', age: 20 })
  },
  tags: {
    type: Array,
    default: () => ['前端', 'Vue']
  }
})

 对象和数组的 default 必须是函数,否则会共享引用!

2. 自定义验证函数

defineProps({
  status: {
    type: String,
    validator(value) {
      // 只允许这几个值
      return ['active', 'inactive', 'pending'].includes(value)
    }
  }
})

传错会直接在控制台报错,开发时非常有用!

3. 必填项

defineProps({
  requiredId: {
    type: Number,
    required: true
  }
})

如果父组件没传,Vue 会警告你。


常见问题 & 最佳实践

Q1:Props 是响应式的吗?

是的! 只要父组件的数据变了,子组件的 props 会自动更新。

但记住:不要在子组件中直接修改它

Q2:我可以给 Props 加 ref 吗?

不要这么做!比如:

const myProp = ref(props.count) // 错误!断开了响应式连接

如果你需要基于 props 做计算,用 computed

import { computed } from 'vue'
const doubleCount = computed(() => props.count * 2)

最佳实践总结

建议 说明
用对象形式定义 Props 支持类型、默认值、验证
对象/数组 default 写成函数 避免引用共享
不要直接修改 Props 用 emit 通知父组件
复杂逻辑用 computed 或 watch 保持响应式
用 v-model 简化双向绑定 代码更简洁

总结:Props 核心要点

概念 说明
作用 父组件向子组件传递数据
特性 单向数据流、只读
修改方式 子组件 emit,父组件修改
语法糖 v-model.sync 简化写法
安全 支持类型、默认值、自定义验证

最后一句话

Props 是组件通信的“高速公路”,但它是单行道——数据只能从父到子。

想要“反向开车”?请走 emit 的“匝道”,由父组件决定是否放行!

掌握好 Props,你的组件才能既灵活安全


网站公告

今日签到

点亮在社区的每一天
去签到