vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > vue3 Props用法

一文详析vue3 Props的用法(父传子)

作者:fishmemory7sec

这篇文章主要给大家介绍了关于vue3 Props的用法(父传子)的相关资料,在Vue3中Props用于组件间数据传递,允许类型检查和默认值设置,文中将用法介绍的非常详细,需要的朋友可以参考下

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

vue官网 Props

Props的作用

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

父组件传值给子组件

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

<ChildComponent title="哈嘿" />

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

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

可以使用 v-bind 动态绑定所有的 props:

可以将一个对象传递给 v-bind,这个对象的属性将被用作组件的 props。

<template>
  <ChildComponent v-bind="obj" />
</template>

<script setup lang="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

<script setup lang="ts">
import { defineProps } from 'vue';

// 字符串数组形式
const props = defineProps(['message', 'count']);
</script>

在这个例子中,声明了两个 Props:message 和count 。

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

<script setup lang="ts">
import { defineProps } from 'vue';

const props = defineProps({
  message: String,
  count: Number,
});
</script>

在这个例子中,声明了两个 Props:message 是字符串类型,count 是数字类型。通过类型注解,TypeScript 可以在开发过程中进行类型检查,确保传入的 props 值符合预期的类型。

在 <script setup> 语法中,使用 defineProps 函数结合类型注解来进行基于类型的声明

如果项目没有使用 TypeScript,就无法使用基于类型的声明进行声明。

基于类型的声明可以在开发过程中利用 TypeScript 的类型检查机制,提前发现类型错误。

export default {
  props: ['message'],
  setup(props) {
    // setup() 接收 props 作为第一个参数
    console.log(props.message)
  }
}

必须要用props选项声明组件接收的Props。如果没有 props: ['message']

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

通过在组件选项对象中直接定义 props 属性来进行运行时声明

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

在这个例子中,message 被声明为字符串类型的 Prop,count 被声明为数字类型的 Prop。这种方式在运行时,Vue 会根据声明的类型对传入的 Props 进行验证。

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

传递给 defineProps() 的参数和提供给 props 选项的值是相同的,本质上都是在使用 prop 选项。

Props 的验证

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

类型验证

<script setup lang="ts">
import { defineProps } from 'vue';
// 定义一个接口作为自定义类型
interface MyCustomType{
  property1: string;
  property2: number;
}
const props = defineProps({
  name: String,
  age: Number,
  hobbies: Array,
  address: Object,
  customType: MyCustomType, // 自定义类型
  onButtonClick: Function   // 函数类型
});
</script>

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

必需性

- 可以指定 Props 是否为必需,如果为必需,则必须在父组件中传入。
<script setup lang="ts">
import { defineProps } from 'vue';

const props = defineProps({
  message: {
    type: String,
    required: true
  }
});
</script>

在这个例子中,message 是必需的 Prop,如果父组件没有传递 message ,则会抛出警告。

自定义验证

- 可以使用 validator 函数进行自定义验证。
<script setup lang="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 时,子组件会使用默认值进行渲染。

<script setup lang="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 参数说明:

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

<template>
  <div>{{ props.message }}</div>
  <div>{{ props.count }}</div>
</template>
<script setup lang="ts">
import { defineProps, withDefaults } from 'vue';

// 定义了一个接口 PropsInter  来描述组件的 props 结构
interface PropsInter {
  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 的行为。

在子组件中:

defineProps({
  disabled: Boolean
})

在父组件中:

<!-- 等同于传入 :disabled="true" -->
<MyComponent disabled />
 
<!-- 等同于传入 :disabled="false" -->
<MyComponent />
const props = defineProps({
  myProp: [Boolean, String],
});

如果父组件传递 "true",这个值将被转换为布尔值 true。如果传递 "false",将被转换为布尔值 false。其他字符串值将保持为字符串。
但是,如果声明顺序是 [String, Boolean],那么 "true" 和 "false" 将被视为字符串,而不会进行布尔类型的转换。

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

使用 Props

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

<ChildComponent title="哈嘿" />

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

<template>
  <div>{{ title }}</div>
</template>
<script setup lang="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>
<script setup lang="ts" name="ChildComponent">
import { defineProps } from "vue";
// 只接收title属性
let props = defineProps(['title'])

console.log(props)

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

defineProps 返回一个对象 propsprops 对象中包含了 title 属性,可以通过 props.title 的方式来访问和使用这个 prop 的值。

defineProps 的返回值是一个包含组件接收的 props 的只读对象:

实战演练

types/index.ts定义一个PersonInter接口:

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

在父组件有一个person传递给子组件:

<template>
  <div>
    <ChildComponent :personList="personList" />
  </div>
</template>

<script setup lang="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>
<script setup lang="ts" name="ChildComponent">
import type { PersonInter } from '@/types';
import { defineProps } from "vue";

// 只接收person
let props = defineProps(['person'])
console.log(props)

// 接收person+类型限制
let props = defineProps<{ person: PersonInter }>()

// 接收person+类型限制+限制必要性+默认值
// ?表示不必传,父组件可传可不传,如果父组件不传,则使用默认值
// 指定默认值需要使用withDefaults
withDefaults(defineProps<{ person?: PersonInter }>(), {
  person: () => {
    return { id: 'person000', name: 'Alice', age: 18 }
  }
})

</script>

总结 

到此这篇关于vue3 Props用法(父传子)的文章就介绍到这了,更多相关vue3 Props用法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文