Props

您所在的位置:网站首页 vue计算属性传参数加set Props

Props

2024-01-29 00:42| 来源: 网络整理| 查看: 265

Props ​

此章节假设你已经看过了组件基础。若你还不了解组件是什么,请先阅读该章节。

Props 声明 ​

一个组件需要显式声明它所接受的 props,这样 Vue 才能知道外部传入的哪些是 props,哪些是透传 attribute (关于透传 attribute,我们会在专门的章节中讨论)。

在使用 的单文件组件中,props 可以使用 defineProps() 宏来声明:

vue const props = defineProps(['foo']) console.log(props.foo)

在没有使用 的组件中,prop 可以使用 props 选项来声明:

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

注意传递给 defineProps() 的参数和提供给 props 选项的值是相同的,两种声明方式背后其实使用的都是 prop 选项。

props 需要使用 props 选项来定义:

jsexport default { props: ['foo'], created() { // props 会暴露到 `this` 上 console.log(this.foo) } }

除了使用字符串数组来声明 prop 外,还可以使用对象的形式:

jsexport default { props: { title: String, likes: Number } }js// 使用 defineProps({ title: String, likes: Number })js// 非 export default { props: { title: String, likes: Number } }

对于以对象形式声明中的每个属性,key 是 prop 的名称,而值则是该 prop 预期类型的构造函数。比如,如果要求一个 prop 的值是 number 类型,则可使用 Number 构造函数作为其声明的值。

对象形式的 props 声明不仅可以一定程度上作为组件的文档,而且如果其他开发者在使用你的组件时传递了错误的类型,也会在浏览器控制台中抛出警告。我们将在本章节稍后进一步讨论有关 prop 校验的更多细节。

TypeScript 用户请参考:为组件 Props 标注类型

如果你正在搭配 TypeScript 使用 ,也可以使用类型标注来声明 props:

vue defineProps()

更多关于基于类型的声明的细节请参考组件 props 类型标注。

传递 prop 的细节 ​Prop 名字格式 ​

如果一个 prop 的名字很长,应使用 camelCase 形式,因为它们是合法的 JavaScript 标识符,可以直接在模板的表达式中使用,也可以避免在作为属性 key 名时必须加上引号。

jsdefineProps({ greetingMessage: String })jsexport default { props: { greetingMessage: String } }template{{ greetingMessage }}

虽然理论上你也可以在向子组件传递 props 时使用 camelCase 形式 (使用 DOM 内模板时例外),但实际上为了和 HTML attribute 对齐,我们通常会将其写为 kebab-case 形式:

template

对于组件名我们推荐使用 PascalCase,因为这提高了模板的可读性,能帮助我们区分 Vue 组件和原生 HTML 元素。然而对于传递 props 来说,使用 camelCase 并没有太多优势,因此我们推荐更贴近 HTML 的书写风格。

静态 vs. 动态 Prop ​

至此,你已经见过了很多像这样的静态值形式的 props:

template

相应地,还有使用 v-bind 或缩写 : 来进行动态绑定的 props:

template 传递不同的值类型 ​

在上述的两个例子中,我们只传入了字符串值,但实际上任何类型的值都可以作为 props 的值被传递。

Number ​template Boolean ​template Array ​template Object ​template 使用一个对象绑定多个 prop ​

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

jsexport default { data() { return { post: { id: 1, title: 'My Journey with Vue' } } } }jsconst post = { id: 1, title: 'My Journey with Vue' }

以及下面的模板:

template

而这实际上等价于:

template单向数据流 ​

所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。这避免了子组件意外修改父组件的状态的情况,不然应用的数据流将很容易变得混乱而难以理解。

另外,每次父组件更新后,所有的子组件中的 props 都会被更新到最新值,这意味着你不应该在子组件中去更改一个 prop。若你这么做了,Vue 会在控制台上向你抛出警告:

jsconst props = defineProps(['foo']) // ❌ 警告!prop 是只读的! props.foo = 'bar'jsexport default { props: ['foo'], created() { // ❌ 警告!prop 是只读的! this.foo = 'bar' } }

导致你想要更改一个 prop 的需求通常来源于以下两种场景:

prop 被用于传入初始值;而子组件想在之后将其作为一个局部数据属性。在这种情况下,最好是新定义一个局部数据属性,从 props 上获取初始值即可:

jsconst props = defineProps(['initialCounter']) // 计数器只是将 props.initialCounter 作为初始值 // 像下面这样做就使 prop 和后续更新无关了 const counter = ref(props.initialCounter)jsexport default { props: ['initialCounter'], data() { return { // 计数器只是将 this.initialCounter 作为初始值 // 像下面这样做就使 prop 和后续更新无关了 counter: this.initialCounter } } }

需要对传入的 prop 值做进一步的转换。在这种情况中,最好是基于该 prop 值定义一个计算属性:

jsconst props = defineProps(['size']) // 该 prop 变更时计算属性也会自动更新 const normalizedSize = computed(() => props.size.trim().toLowerCase())jsexport default { props: ['size'], computed: { // 该 prop 变更时计算属性也会自动更新 normalizedSize() { return this.size.trim().toLowerCase() } } }更改对象 / 数组类型的 props ​

当对象或数组作为 props 被传入时,虽然子组件无法更改 props 绑定,但仍然可以更改对象或数组内部的值。这是因为 JavaScript 的对象和数组是按引用传递,而对 Vue 来说,禁止这样的改动,虽然可能生效,但有很大的性能损耗,比较得不偿失。

这种更改的主要缺陷是它允许了子组件以某种不明显的方式影响父组件的状态,可能会使数据流在将来变得更难以理解。在最佳实践中,你应该尽可能避免这样的更改,除非父子组件在设计上本来就需要紧密耦合。在大多数场景下,子组件应该抛出一个事件来通知父组件做出改变。

Prop 校验 ​

Vue 组件可以更细致地声明对传入的 props 的校验要求。比如我们上面已经看到过的类型声明,如果传入的值不满足类型要求,Vue 会在浏览器控制台中抛出警告来提醒使用者。这在开发给其他开发者使用的组件时非常有用。

要声明对 props 的校验,你可以向 defineProps() 宏props 选项提供一个带有 props 校验选项的对象,例如:

jsdefineProps({ // 基础类型检查 // (给出 `null` 和 `undefined` 值则会跳过任何类型检查) propA: Number, // 多种可能的类型 propB: [String, Number], // 必传,且为 String 类型 propC: { type: String, required: true }, // Number 类型的默认值 propD: { type: Number, default: 100 }, // 对象类型的默认值 propE: { type: Object, // 对象或数组的默认值 // 必须从一个工厂函数返回。 // 该函数接收组件所接收到的原始 prop 作为参数。 default(rawProps) { return { message: 'hello' } } }, // 自定义类型校验函数 // 在 3.4+ 中完整的 props 作为第二个参数传入 propF: { validator(value, props) { // The value must match one of these strings return ['success', 'warning', 'danger'].includes(value) } }, // 函数类型的默认值 propG: { type: Function, // 不像对象或数组的默认,这不是一个 // 工厂函数。这会是一个用来作为默认值的函数 default() { return 'Default function' } } })

TIP

defineProps() 宏中的参数不可以访问 中定义的其他变量,因为在编译时整个表达式都会被移到外部的函数中。

jsexport default { props: { // 基础类型检查 //(给出 `null` 和 `undefined` 值则会跳过任何类型检查) propA: Number, // 多种可能的类型 propB: [String, Number], // 必传,且为 String 类型 propC: { type: String, required: true }, // Number 类型的默认值 propD: { type: Number, default: 100 }, // 对象类型的默认值 propE: { type: Object, // 对象或者数组应当用工厂函数返回。 // 工厂函数会收到组件所接收的原始 props // 作为参数 default(rawProps) { return { message: 'hello' } } }, // 自定义类型校验函数 // 在 3.4+ 中完整的 props 作为第二个参数传入 propF: { validator(value, props) { // The value must match one of these strings return ['success', 'warning', 'danger'].includes(value) } }, // 函数类型的默认值 propG: { type: Function, // 不像对象或数组的默认,这不是一个 // 工厂函数。这会是一个用来作为默认值的函数 default() { return 'Default function' } } } }

一些补充细节:

所有 prop 默认都是可选的,除非声明了 required: true。

除 Boolean 外的未传递的可选 prop 将会有一个默认值 undefined。

Boolean 类型的未传递 prop 将被转换为 false。这可以通过为它设置 default 来更改——例如:设置为 default: undefined 将与非布尔类型的 prop 的行为保持一致。

如果声明了 default 值,那么在 prop 的值被解析为 undefined 时,无论 prop 是未被传递还是显式指明的 undefined,都会改为 default 值。

当 prop 的校验失败后,Vue 会抛出一个控制台警告 (在开发模式下)。

如果使用了基于类型的 prop 声明 ,Vue 会尽最大努力在运行时按照 prop 的类型标注进行编译。举例来说,defineProps 会被编译为 { msg: { type: String, required: true }}。

注意

注意 prop 的校验是在组件实例被创建之前,所以实例的属性 (比如 data、computed 等) 将在 default 或 validator 函数中不可用。

运行时类型检查 ​

校验选项中的 type 可以是下列这些原生构造函数:

StringNumberBooleanArrayObjectDateFunctionSymbol

另外,type 也可以是自定义的类或构造函数,Vue 将会通过 instanceof 来检查类型是否匹配。例如下面这个类:

jsclass Person { constructor(firstName, lastName) { this.firstName = firstName this.lastName = lastName } }

你可以将其作为一个 prop 的类型:

jsdefineProps({ author: Person })jsexport default { props: { author: Person } }

Vue 会通过 instanceof Person 来校验 author prop 的值是否是 Person 类的一个实例。

Boolean 类型转换 ​

为了更贴近原生 boolean attributes 的行为,声明为 Boolean 类型的 props 有特别的类型转换规则。以带有如下声明的 组件为例:

jsdefineProps({ disabled: Boolean })jsexport default { props: { disabled: Boolean } }

该组件可以被这样使用:

template

当一个 prop 被声明为允许多种类型时,Boolean 的转换规则也将被应用。然而,当同时允许 String 和 Boolean 时,有一种边缘情况——只有当 Boolean 出现在 String 之前时,Boolean 转换规则才适用:

js// disabled 将被转换为 true defineProps({ disabled: [Boolean, Number] }) // disabled 将被转换为 true defineProps({ disabled: [Boolean, String] }) // disabled 将被转换为 true defineProps({ disabled: [Number, Boolean] }) // disabled 将被解析为空字符串 (disabled="") defineProps({ disabled: [String, Boolean] })js// disabled 将被转换为 true export default { props: { disabled: [Boolean, Number] } } // disabled 将被转换为 true export default { props: { disabled: [Boolean, String] } } // disabled 将被转换为 true export default { props: { disabled: [Number, Boolean] } } // disabled 将被解析为空字符串 (disabled="") export default { props: { disabled: [String, Boolean] } }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3