2-2-vue框架-组件-vue-component组件化开发-组件的传值(父传子)
背景
如果我们正在构建一个博客,我们可能需要一个表示博客文章的组件。我们希望所有的博客文章分享相同的视觉布局,但有不同的内容。要实现这样的效果自然必须向组件中传递数据,例如每篇文章标题和内容,这就会使用到 props。
定义一个含props的组件
Props 是一种特别的 attributes,你可以在组件上声明注册。要传递给博客文章组件一个标题,我们必须在组件的 props 列表上声明它。这里要用到 props 选项
<!-- BlogPost.vue -->
<template>
<h4>{{ title }}</h4>
</template>
<script>
export default {
props: ['title']
}
</script>
- 所以props必须要在组件中声明,这样 Vue 才能知道外部传入的哪些是 props,
- 当一个值被传递给 prop 时,它将成为该组件实例上的一个属性。该属性的值可以像其他组件属性一样,在模板和组件的 this 上下文中访问。
-一个组件可以有任意多的 props,默认情况下,所有 prop 都接受任意类型的值。
除了使用字符串数组来声明 prop 外,还可以使用对象的形式:
export default {
props: {
title: String,
likes: Number
}
}
-
对于以对象形式声明中的每个属性,key 是 prop 的名称,而值则是该 prop 预期类型的构造函数。比如,如果要求一个 prop 的值是 number 类型,则可使用 Number 构造函数作为其声明的值。
-
对象形式的 props 声明不仅可以一定程度上作为组件的文档,而且如果其他开发者在使用你的组件时传递了错误的类型,也会在浏览器控制台中抛出警告。
使用一个props的组件
静态传props
<template>
<BlogPost title="My journey with Vue" />
<BlogPost title="Blogging with Vue" />
<BlogPost title="Why Vue is so fun" />
</template>
<script>
import BlogPost from "./components/demo1.vue"
export default {
components:{
BlogPost
},
}
</script>
动态传props
在实际应用中,更可能是这样写
<template>
<BlogPost
v-for="post in posts"
:key="post.id"
:title="post.title"
/>
</template>
<script>
import BlogPost from "./components/demo1.vue"
export default {
components:{
BlogPost
},
data() {
return {
posts: [
{ id: 1, title: 'My journey with Vue' },
{ id: 2, title: 'Blogging with Vue' },
{ id: 3, title: 'Why Vue is so fun' }
]
}
}
}
</script>
- 留意我们是如何使用 v-bind 来传递动态 prop 值的。当事先不知道要渲染的确切内容时,这一点特别有用。
- 传入的值可以是任意类型,比如数字,字符串,列表,对象,都可以,
单向数据流
所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。这避免了子组件意外修改父组件的状态的情况,不然应用的数据流将很容易变得混乱而难以理解。
不允许子组件修改prop,会报异常
另外,每次父组件更新后,所有的子组件中的 props 都会被更新到最新值,这意味着你不应该在子组件中去更改一个 prop。
若你这么做了,Vue 会在控制台上向你抛出警告
情况1:prop 被用于传入初始值;而子组件想在之后将其作为一个局部数据属性
新定义一个局部数据属性,从 props 上获取初始值即可
情况2:需要对传入的 prop 值做进一步的转换。
在这种情况中,最好是基于该 prop 值定义一个计算属性
更改对象 / 数组类型的 props
-
可以改
子组件可以更改对象或数组内部的值。这是因为 JavaScript 的对象和数组是按引用传递, -
但是禁止改
而对 Vue 来说,禁止这样的改动,虽然可能生效,但有很大的性能损耗,比较得不偿失。
危害:会让代码变得混乱,而且难以理解
- 缺陷是它允许了子组件以某种不明显的方式影响父组件的状态,可能会使数据流在将来变得更难以理解。在最佳实践中,你应该尽可能避免这样的更改,除非父子组件在设计上本来就需要紧密耦合。在大多数场景下,子组件应该抛出一个事件来通知父组件做出改变。
组件内对Prop 校验
如果在组件内,我想要让这个属性必传,或者对属性进行校验怎么办?
要声明对 props 的校验,你可以向 props 选项提供一个带有 props 校验选项的对象,例如:
export 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' }
}
},
// 自定义类型校验函数
propF: {
validator(value) {
// 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 会抛出一个控制台警告
这是类型的种类:
String
Number
Boolean
Array
Object
Date
Function
Symbol