0


vue3 Props的用法(父传子)

在 Vue 3 中,Props(属性)用于在组件之间传递数据。

vue官网 Props

Props的作用

  1. 传参:Props 允许父组件向子组件传递数据。
  2. 类型检查:Vue 允许在定义 Props 时指定数据的类型,这有助于在开发过程中进行类型检查,提前发现潜在的类型错误。
  3. 设置默认值:可以为 Props 设置默认值。当父组件没有传递该 Prop 时,子组件会使用默认值进行渲染。

Vue 中的 Props 遵循单向数据流原则,即父组件向子组件传递数据,子组件不能直接修改父组件传递过来的 Prop。

父组件传值给子组件

在父组件的模板中,可以使用属性绑定的方式将数据传递给子组件(静态传值):

<ChildComponenttitle="哈嘿"/>

可以使用变量或表达式来动态地传递 Props:

<!-- 根据一个变量的值动态传入 --><ChildComponent:title="title"/><!-- 根据一个更复杂表达式的值动态传入 --><ChildComponent:title="someCondition ? titleA : titleB"/>

可以使用

v-bind

动态绑定所有的 props:
可以将一个对象传递给

v-bind

,这个对象的属性将被用作组件的 props。

<template><ChildComponentv-bind="obj"/></template><scriptsetuplang="ts">import ChildComponent from'./ChildComponent.vue';import{ reactive }from'vue'let obj =reactive({message:'Hello',count:5})</script>
<ChildComponent v-bind="obj" />

等价于:

<ChildComponent:message="message":count="count"/>

声明 Props

  1. 使用 defineProps 函数: - 在 <script setup> 语法中,可以直接使用 defineProps 函数来声明组件接收的 Props。- 在 Vue 3 中,基于类型的声明通常用于组合式 API 。
<scriptsetuplang="ts">import{ defineProps }from'vue';// 字符串数组形式const props =defineProps(['message','count']);</script>

在这个例子中,声明了两个 Props:

message

count

可以使用对象字面量的方式来声明 Props:

<scriptsetuplang="ts">import{ defineProps }from'vue';const props =defineProps({message: String,count: Number,});</script>

在这个例子中,声明了两个 Props:

message

是字符串类型,

count

是数字类型。通过类型注解,TypeScript 可以在开发过程中进行类型检查,确保传入的 props 值符合预期的类型。

<script setup>

语法中,使用

defineProps

函数结合类型注解来进行基于类型的声明
如果项目没有使用 TypeScript,就无法使用基于类型的声明进行声明。
基于类型的声明可以在开发过程中利用 TypeScript 的类型检查机制,提前发现类型错误。

  1. 在选项式 API 中(没有使用 <script setup> 语法糖),props 是通过 props 选项进行声明的。 - 必须要用props选项声明组件接收的Props,在setup()props参数里,才有Props数据。- 在 Vue 3 中,运行时声明通常用于选项式 API。
exportdefault{props:['message'],setup(props){// setup() 接收 props 作为第一个参数
    console.log(props.message)}}

必须要用

props

选项声明组件接收的Props。如果没有

props: ['message']

exportdefault{setup(props){// 报错: 类型“LooseRequired<{} & {}>”上不存在属性“message”。
    console.log(props.message)}}

通过在组件选项对象中直接定义

props

属性来进行运行时声明

exportdefault{props:{message: String,count: Number,},setup(){}// 组件的其他选项和逻辑};

在这个例子中,

message

被声明为字符串类型的 Prop,

count

被声明为数字类型的 Prop。这种方式在运行时,Vue 会根据声明的类型对传入的 Props 进行验证。

运行时声明通常在不需要进行严格类型检查或者需要更灵活地处理 Props 的情况下使用。它主要依赖于 Vue 的运行时机制来处理 Props 的传递和验证。

传递给

defineProps()

的参数和提供给

props

选项的值是相同的,本质上都是在使用

prop

选项。

Props 的验证

Props 验证的主要目的是确保组件接收到的数据符合预期的格式和类型。

类型验证

  • 可以指定 Props 的类型,如 StringNumberBooleanArrayObject 等。
  • 也可以是函数类型 Function 、自定义类型。
<scriptsetuplang="ts">import{ defineProps }from'vue';// 定义一个接口作为自定义类型interfaceMyCustomType{property1: string;property2: number;}const props =defineProps({name: String,age: Number,hobbies: Array,address: Object,customType: MyCustomType,// 自定义类型onButtonClick: Function   // 函数类型});</script>

确保父组件传递给子组件的Props值与声明的类型一致,避免类型错误。

必需性

- 可以指定 Props 是否为必需,如果为必需,则必须在父组件中传入。
<scriptsetuplang="ts">import{ defineProps }from'vue';const props =defineProps({message:{type: String,required:true}});</script>

在这个例子中,

message

是必需的 Prop,如果父组件没有传递

message

,则会抛出警告。

自定义验证

- 可以使用 validator 函数进行自定义验证。
<scriptsetuplang="ts">import{ defineProps }from"vue";let props =defineProps({b:{type: Number,validator:(value: number)=>{return value >=0;// 自定义验证,确保宽度非负}}})
console.log(props)</script>

在这个例子中,

b

使用了自定义验证函数,确保

b

的值不为负数。
在父组件传入

b = -10

,浏览器控制台输出警告:
在这里插入图片描述

默认值

可以为 Props 设置默认值,当父组件没有传递该 Prop 时,子组件会使用默认值进行渲染。

<scriptsetuplang="ts">import{ defineProps }from'vue';const props =defineProps({message:{type: String,default:'Hello, Vue 3!',},count:{type: Number,default:0,},});</script>

在这个例子中,

message

的默认值为

'Hello, Vue 3!'

count

的默认值为

0

withDefaults

在 Vue 3 中,

withDefaults

是一个用于为

defineProps

定义的 props 设置默认值的函数。

withDefaults

参数说明:

  • withDefaults 的第一个参数是 defineProps 的返回值,它表示组件接收的 props 对象。
  • 第二个参数是一个对象,其中的键对应于 props 的名称,值是相应的默认值。 - 默认值是通过函数返回的。

假设有一个组件,定义了一些 props,并且希望为其中一些 props 设置默认值:

<template><div>{{ props.message }}</div><div>{{ props.count }}</div></template><scriptsetuplang="ts">import{ defineProps, withDefaults }from'vue';// 定义了一个接口 PropsInter  来描述组件的 props 结构interfacePropsInter{message: string;count: number;obj:{a: number; b: number;};arr: string[];}const props =withDefaults(defineProps<PropsInter>(),{message:'Hello, Vue 3!',count:0,obj:()=>{return{a:10,b:5}},arr:()=>return['item1','item2']});</script>

Boolean 类型转换

当声明为

Boolean

类型的

props

时,有特别的类型转换规则,以便更贴近原生的 boolean attributes 的行为。

  • 当一个 prop 明确被声明为布尔类型时,真值会被转换为 true,假值会被转换为 false: - 当父组件传递一个真值(如 true、字符串 "true"、数字 1 等)时,该 prop 将被转换为 true。- 当父组件传递一个假值(如 false、字符串 "false"、数字 0、空字符串 ""nullundefined 等)时,该 prop 将被转换为 false

在子组件中:

defineProps({
  disabled: Boolean
})

在父组件中:

<!-- 等同于传入 :disabled="true" --><MyComponentdisabled/><!-- 等同于传入 :disabled="false" --><MyComponent/>
  • 当一个 prop 被声明为允许多种类型时,声明顺序会影响 Boolean 转换规则是否适用: - 当同时允许字符串和布尔类型时,如果布尔类型出现在字符串类型之前,Boolean 转换规则才适用。
const props =defineProps({
  myProp:[Boolean, String],});

如果父组件传递

"true"

,这个值将被转换为布尔值

true

。如果传递

"false"

,将被转换为布尔值

false

。其他字符串值将保持为字符串。
但是,如果声明顺序是

[String, Boolean]

,那么

"true"

"false"

将被视为字符串,而不会进行布尔类型的转换。

这种边缘情况可能会导致在不同的声明顺序下,相同的输入值被解释为不同的类型。

使用 Props

在父组件的模板中传值给子组件:

<ChildComponenttitle="哈嘿"/>

在子组件的模板中,可以直接使用定义的 Props:

<template><div>{{ title }}</div></template><scriptsetuplang="ts"name="ChildComponent">import{ defineProps }from"vue";defineProps(['title'])// console.log(title)  // 报错:找不到名称“title”。</script>

在模板中,可以直接使用

title

console.log(title)

报错:找不到名称“title”。
这是因为

title

并没有被直接声明为一个可用的变量。

**在 Vue 3 的

<script setup>

中,

defineProps

的返回值是一个包含传入的 props 的对象。**

如果想要在组件中使用

title

,需要通过

defineProps

的返回值来读取:

<template><div>{{ props.title }}</div></template><scriptsetuplang="ts"name="ChildComponent">import{ defineProps }from"vue";// 只接收title属性let props =defineProps(['title'])

console.log(props)if(props.title){
  console.log(props.title)}</script>
defineProps

返回一个对象

props

props

对象中包含了

title

属性,可以通过

props.title

的方式来访问和使用这个 prop 的值。
在这里插入图片描述

defineProps

的返回值是一个包含组件接收的

props

的只读对象:

  • 返回的 props 对象是只读的。
  • 返回的 props 对象包含了组件所有接收的东西:父组件传递给当前组件的所有被组件明确声明为 props 的属性。 - 必须在defineProps中显式的接收父组件传递的属性。假如父组件传了几个属性,比如<ChildComponent title="哈嘿" id="id12345" />,子组件defineProps(['title'])只接收title属性,不会接收id属性。
  • 在组件内部不能直接修改 props 对象的属性值。

实战演练

types/index.ts

定义一个

PersonInter

接口:

// 定义一个接口,用于限制对象的具体属性// 接口在 TypeScript 中用于定义一种契约,确保实现该接口的对象都具有相同的结构。exportinterfacePersonInter{
  id:string;
  name:string;
  age:number;}

在父组件有一个

person

传递给子组件:

<template><div><ChildComponent:personList="personList"/></div></template><scriptsetuplang="ts"name="Person">// 在 TypeScript 中,import type 语法用于仅导入类型信息而不导入实际的值或函数。// 使用 import type 导入的类型信息仅在类型检查时使用,不会在运行时产生任何影响。import type { PersonInter }from'@/types';import{ reactive }from'vue';import ChildComponent from'./ChildComponent.vue';let personList = reactive<PersonInter>({id:'person001',name:'John',age:18});</script>

子组件:

<template><div>{{ person.name }}</div></template><scriptsetuplang="ts"name="ChildComponent">import type { PersonInter }from'@/types';import{ defineProps }from"vue";// 只接收personlet props =defineProps(['person'])
console.log(props)// 接收person+类型限制let props = defineProps<{person: PersonInter }>()// 接收person+类型限制+限制必要性+默认值// ?表示不必传,父组件可传可不传,如果父组件不传,则使用默认值// 指定默认值需要使用withDefaultswithDefaults(defineProps<{ person?: PersonInter }>(),{person:()=>{return{id:'person000',name:'Alice',age:18}}})</script>
  • let props = defineProps(['person']) 只接收person,对person没有任何限制。父组件可以给person赋任意类型的值。
  • defineProps<{ person: PersonInter }>(): 通过泛型参数指定了 props 的结构。具体来说,定义了一个名为 person 的 prop,其类型为 PersonInter
  • defineProps<{ person?: PersonInter }>(): - 使用泛型参数指定了 props 的结构。定义了一个名为 person 的 prop,其类型为 PersonInter。- 后面的问号 ? 表示这个 prop 是可选的,即父组件可以选择是否传递这个 prop。

本文转载自: https://blog.csdn.net/fishmemory7sec/article/details/141467033
版权归原作者 fishmemory7sec 所有, 如有侵权,请联系我们删除。

“vue3 Props的用法(父传子)”的评论:

还没有评论