注意:vue组件中的data必须为一个函数,要不vue就会停止工作。
构成组件
组件意味着协同工作,通常父子组件会是这样的关系:组件A在它的模板中使用了组件B,他们之间必然需要相互通信:父组件需要给子组件传递数据,子组件需要将它内部的发生的事情告诉父组件。然而,在一个良好定义的接口中尽可能将父子组件解耦是很重要的。这保证了每个组件在相对隔离的环境中书写和理解,也大幅提高了组件的可维护性和可重用性。
在vue中,父子组件的关系可以总结为props down和events up;父组件通过props向下传递数据给子组件。子组件通过events给父组件发送消息。
prop
使用prop传递数据
组件实例的作用域是孤立的。这意味着不能(也不应该)在子组件的模板内直接引用父组件的数据。要让子组件使用父组件中的数据。我们需要使用子组件的props选项。
子组件要显式地用props选项声明它要获得的数据。
Vue.component(‘child‘, {
// 声明 props
props: [‘message‘],
// 就像 data 一样,prop 可以用在模板内
// 同样也可以在 vm 实例中像“this.message”这样使用
template: ‘<span>{{ message }}</span>‘
})
然后我们可以这样向它传入一个普通字符串:
<child message="hello!"></child>
结果:hello!
camelCase vs. kebab-case
html特性是不区分大小写的。所以当使用的不是字符串模板时,camelCased(驼峰式)命名的prop需要转换为相对应的kebab-case(短横线隔开式)命名:
Vue.component(‘child‘, {
// camelCase in JavaScript
props: [‘myMessage‘],
template: ‘<span>{{ myMessage }}</span>‘
})
<!-- kebab-case in HTML -->
<child my-message="hello!"></child>
动态prop
在模板中,要动态的绑定父组件的数据到子模板的props,与绑定到任何普通的html特性相类似,就是用v-bind,每当父组件的数据发生变化时,该变化也会传导给子组件。
<div>
<input v-model="parentMsg">
<br>
<child v-bind:my-message="parentMsg"></child>
</div>
使用 v-bind
的缩写语法通常更简单:
<child :my-message="parentMsg"></child>
字面量语法vs动态语法
初学者常犯的错误是使用字面量语法传递数值。
<!-- 传递了一个字符串 "1" -->
<comp some-prop="1"></comp>
因为它是一个字面prop,它的值是字符串“1”,而不是number.如果想传递一个实际的number,需要使用v-bind,从而让它的值被当作javascript表达式计算:
<!-- 传递实际的 number -->
<comp v-bind:some-prop="1"></comp>
单向数据流
prop是单向绑定的:当父组件的属性变化时,将传导给子组件,但不会反过来。这是为了防止子组件无意修改了父组件的状态--这会让应用的数据流很难理解。
另外,每次父组件更新时,子组件的所有prop都会更新为最新值。这意味着你不应该在子组件内部改变prop。如果你这么做了,vue会在控制台报出警告。
为什么我们会有修改prop的冲动,通常有两个原因:
1,prop作为初始值传入后,子组件想把它当做局部数据来用,
2,prop作为初始值传入,由子组件处理成其他数据输出。
对这两种原因,正确的应对方式是:
1,定义一个局部变量,并用prop的值初始化它。
props: [‘initialCounter‘],
data: function () {
return { counter: this.initialCounter }
}
2,定义一个计算属性,处理prop的值并返回。
props: [‘size‘],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
注意在javascript中对象和数组是引用类型,指向同一个内存空间,如果prop是一个对象或数组,在子组件内部改变它会影响父组件的状态。
prop验证
我们可以为组建的props指定验证规格。如果传入的数据不符合规格,vue会发出警告。当组件给其他人使用时,这很有用。
要指定验证规格,我们需要用对象的形式,而不能用字符串数组:
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也可以是一个自定义的构造器函数,使用instance of检测。
当prop验证失败,vue 会抛出警告(如果使用的是开发版本).注意props会在组件实例创建之前进项校验,所以在default或validator函数里。诸如data,computed,或methods等实例属性还无法使用。