Props

1、声明:

  • 在使用 <script setup> 的单文件组件中,props 可以使用 defineProps() 宏来声明:
//字符串数组声明
<script setup>
const props = defineProps(['foo'])

console.log(props.foo)
</script>


//对象形式的声明
defineProps({
  title: String,
  likes: Number
})
  • -在没有使用 <script setup> 的组件中,props 可以使用 props 选项来声明:
//字符串数组声明
export default {
  props: ['foo'],
  setup(props) {
    // setup() 接收 props 作为第一个参数
    console.log(props.foo)
  }
}

//对象形式的声明
export default {
  props: {
    title: String,
    likes: Number
  }
}

2、解构响应式Props

<template>
  <div>{{ foo }}</div>
 </template>
 <script setup>
  // 在3.4及以下,foo是一个常量,不会响应式更新;父组件传递的数据更改时,foo不会改变
  // 在3.5及以上,foo是响应式的,Vue会自动添加props.前缀
  const { foo } = defineProps(['foo']);
 </script>

3、将解构的props传递到函数中

当我们将解构的prop传递到watch函数中去:

const { foo } = defineProps(['foo'])

1、watch(foo, /* ... */)     //错误
2、watch(() => foo, /* ... */)    //正确

第一种方式错误是因为:给 watch 传递的是一个值而不是响应式数据源,而watch监听的应该是一个可变的数据,不然没有意义。而且Vue 的编译器会捕捉这种情况并发出警告

第二种方式正确是因为:确保了对foo(或props.foo)的依赖收集,按照Vue的响应式原理,能够在foo变化时触发对应的回调

4、传递prop的细节

Prop名字格式:

//子组件接收数据时用小驼峰
defineProps({
  greetingMessage: String
})

//父组件向子组件传递props时使用羊肉串( kebab-case 形式)
<MyComponent greeting-message="hello" />

静态 vs. 动态 Props

//静态
<BlogPost title="My journey with Vue" />

//动态
<!-- 根据一个变量的值动态传入 -->
<BlogPost :title="post.title" />

<!-- 根据一个更复杂表达式的值动态传入 -->
<BlogPost :title="post.title + ' by ' + post.author.name" />

使用一个对象绑定多个 prop

如果你想要将一个对象的所有属性都当作 props 传入,你可以使用没有参数的 v-bind,即只使用 v-bind 而非 :prop-name

//假设这是要传入的一个对象
const post = {
  id: 1,
  title: 'My Journey with Vue'
}
<BlogPost v-bind="post" />   ====   <BlogPost :id="post.id" :title="post.title" />

5、单向数据流

所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递

注:子组件中数据的更新是由父组件数据更新后流下来的,而不是在子组件中去更改prop,prop只是可读

想更改prop的一般是两个场景:

1、prop 被用于传入初始值;而子组件想在之后将其作为一个局部数据属性

const props = defineProps(['initialCounter'])

// 计数器只是将 props.initialCounter 作为初始值
// 像下面这样做就使 prop 和后续更新无关了
const counter = ref(props.initialCounter)

2、需要对传入的 prop 值做进一步的转换,最好是利用计算属性:

const props = defineProps(['size'])

// 该 prop 变更时计算属性也会自动更新
const normalizedSize = computed(() => props.size.trim().toLowerCase())

6、更改对象 / 数组类型的 props

当对象或数组作为 props 被传入时,虽然子组件无法更改 props 绑定,但仍然可以更改对象或数组内部的值

原因:JavaScript 的对象和数组是按引用传递,对 Vue 来说,阻止这种更改需要付出的代价异常昂贵。

弊端:它允许了子组件以某种不明显的方式影响父组件的状态,可能会使数据流在将来变得更难以理解

解决措施:在大多数场景下,子组件应该抛出一个事件来通知父组件做出改变

7、细节

  • 所有 prop 默认都是可选的,除非声明了 required: true
  • 除 Boolean 外的未传递的可选 prop 将会有一个默认值 undefined
  • Boolean 类型的未传递 prop 将被转换为 false。这可以通过为它设置 default 来更改——例如:设置为 default: undefined 将与非布尔类型的 prop 的行为保持一致。
  • 如果该类型是必传但可为 null 的,你可以用一个包含 null 的数组语法:
defineProps({
  id: {
    type: [String, null],
    required: true
  }
})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

khatung

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值