vue组件之prop
在Vue 中,父子组件的关系可以总结为 props down, events up。
父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息。
在介绍props之前,先说说父子级组件的写法
在一个良好定义的接口中尽可能将父子组件解耦是很重要的。这保证了每个组件可以在相对隔离的环境中书写和理解,也大幅提高了组件的可维护性和可重用性
<div id="example">
<parent>
<child></child>
<child></child>
</parent>
</div>
<div id="example">
<parent></parent>
<child></child>
</div>
// 这样的写法都是错误的
Prop 的大小写 (camelCase vs kebab-case)
子组件内部命名的camelCase (驼峰命名法)或者kebab-case (短横线分隔命名) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名
在父级HTML模板中,属性名需要使用中划线写法
子级props属性声明时,使用驼峰或者中划线写法都可以;而子级模板使用从父级传来的变量时,需要使用对应的驼峰写法,
组件实例的作用域是孤立的。这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据。要让子组件使用父组件的数据,需要通过子组件的 props 选项
使用Prop传递数据包括静态和动态两种形式,下面先介绍静态props
静态props
静态Prop通过为子组件在父组件中的占位符添加特性的方式来达到传值的目的
<div class="parent">
<child message="aaa"></child>
<child message="bbb"></child>
</div>
//child
var childNode = {
template: '<div>{{message}}</div>',
props:['message']
}
动态props
在模板中,要动态地绑定父组件的数据到子模板的 props,与绑定到任何普通的HTML特性相类似,就是用 v-bind。每当父组件的数据变化时,该变化也会传导给子组件
<div class="parent">
<child :my-message="data1"></child>
<child :my-message="data2"></child>
</div>
传递数字 误区
<child my-message="1"></child>
<child :my-message="1"></child>
有编辑器的颜色,一般很容易发现错误
props验证
可以为组件的 props 指定验证规格。如果传入的数据不符合规格,Vue会发出警告。当组件给其他人使用时,这很有用 一般子组件接收的时候习惯数组字符串的形式。
一般我们用来校验传入进来的数据的数据类型,要指定验证规格,需要用对象的形式,而不能用字符串数组
props:['propsA','propsB']
Vue.component('example', {
props: {
// 基础类型检测 (`null` 意思是任何类型都可以)
propA: Number,
// 多种类型
propB: [String, Number],
// 必传且是字符串
propC: {
type: String,
required: true
},
// 数字,有默认值
propD: {
type: Number,
default: 100
},
// 数组/对象的默认值应当由一个工厂函数返回
propE: {
type: Object,
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
return value > 10
}
}
}
})
// type可以使以下的原生构造器
String
Number
Boolean
Function
Object
Array
Symbol
type 也可以是一个自定义构造器函数,使用 instanceof 检测。
var childNode = {
template: '<div>{{message}}</div>',
props:{
'message':{
validator: function (value) {
return value > 10
}
}
}
}
props会在组件实例创建之前进行校验,所以在 default 或 validator 函数里,诸如 data、computed 或 methods 等实例属性还无法使用
单向数据流
prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。这是为了防止子组件无意修改了父组件的状态——这会让应用的数据流难以理解
所以不应该在子组件内部改变prop
修改prop数据
修改prop中的数据,通常有以下两种原因
1、prop 作为初始值传入后,子组件想把它当作局部数据来用
2、prop 作为初始值传入,由子组件处理成其它数据输出
对于这两种情况,正确的应对方式是
1. 定义一个局部变量,并用 prop 的值初始化它
props: ['initialCounter'],
data: function () {
return { counter: this.initialCounter }
}
但是,定义的局部变量counter只能接受initialCounter的初始值,当父组件要传递的值发生变化时,counter无法接收到最新值
2. 定义一个计算属性,处理 prop 的值并返回
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
但是,由于是计算属性,则只能显示值,而不能设置值
- 更加妥帖的方案是,使用变量储存prop的初始值,并使用watch来观察prop的值的变化。发生变化时,更新变量的值
props:['childMsg'],
watch:{
childMsg(){
this.temp = this.childMsg
}
}
需要注意的是:prop传进来的数据是对象和数组的时候,注意他们是引用类型的数据,指向同一个内存空间,在子组件内改变,它会影响父组件的状态