构造Vue实例时传入的各种选项大多数都可以在组件里使用。只有一个例外:data必须是函数。实际上如果你这么做:
Vue.component('my-component', {
template: '<span>{{ message }}</span>',
data: {
message: 'hello'
}
})
那么vue会停止运行,并在控制台发出警告,告诉你在组件实例中data必须是一个函数,
data: function () {
return {
counter: 0
}
}
<div id="example-2">
<simple-counter></simple-counter>
<simple-counter></simple-counter>
<simple-counter></simple-counter>
</div>
var data = { counter: 0 }
Vue.component('simple-counter', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
// 技术上 data 的确是一个函数了,因此 Vue 不会警告,
// 但是我们却给每个组件实例返回了同一个对象的引用
data: function () {
return data
}
})
new Vue({
el: '#example-2'
})
由于这三个组件实例共享了同一个 data
对象,因此递增一个 counter 会影响所有组件!这就错了。我们可以通过为每个组件返回全新的数据对象来修复这个问题:
现在每个counter都有自己内部的状态了。
#组件组合
组件设计初衷就是要配合使用的,最常见的就是形成父子组件的关系:组件 A 在它的模板中使用了组件 B。它们之间必然需要相互通信:父组件可能要给子组件下发数据,子组件则可能要将它内部发生的事情告知父组件。然而,通过一个良好定义的接口来尽可能将父子组件解耦也是很重要的。这保证了每个组件的代码可以在相对隔离的环境中书写和理解,从而提高了其可维护性和复用性。
在 Vue 中,父子组件的关系可以总结为 prop 向下传递,事件向上传递。父组件通过 prop给子组件下发数据,子组件通过事件给父组件发送消息。看看它们是怎么工作的。
prop
#使用Prop传递数据
组件实例的作用域是孤立的。这意味着不能(也不应该)在子组件的模板里引用父组件的数据,父组件的数据需要通过prop才能下发到子组件中。
子组件要显示的用props选项声明它预期的数据:
Vue.component('child', {
// 声明 props
props: ['message'],
// 就像 data 一样,prop 也可以在模板中使用
// 同样也可以在 vm 实例中通过 this.message 来使用
template: '<span>{{ message }}</span>'
})
然后我们可以这样向它传入一个普通字符串:
<child message="hello!"></child>
#camelCase vs.kebab-case
Html的特性是不区分大小写的,如果使用的不是字符串模板,需要把prop里的camelCase(驼峰式命名)转换为(kebab-case)短杠形式。
Vue.component('child', {
// 在 JavaScript 中使用 camelCase
props: ['myMessage'],
template: '<span>{{ myMessage }}</span>'
})
<!-- 在 HTML 中使用 kebab-case -->
<child my-message="hello!"></child>
如果使用字符串模板则没有这些限制。
#动态Prop
与绑定到任何的普通HTML特性相类似,我们可以用v-bind来动态的将prop绑定到父组件的数据。每当父组件的数据变化时,该变化也会传导给子组件:
<div id="prop-example-2">
<input v-model="parentMsg">
<br>
<child v-bind:my-message="parentMsg"></child>
</div>
new Vue({
el: '#prop-example-2',
data: {
parentMsg: 'Message from parent'
}
})
你也可以使用 v-bind
的缩写语法:
<child :my-message="parentMsg"></child> |
如果你想把一个对象的所有属性作为prop进行传递,可以使用不带任何参数的v-bind(即用v-bind 而不是v-bind:prop-name)。例如已知一个todo对象。
todo: {
text: 'Learn Vue',
isComplete: false
}
<todo-item v-bind="todo"></todo-item>
将等价于:
<todo-item
v-bind:text="todo.text"
v-bind:is-complete="todo.isComplete"
></todo-item>
#字面量语法vs动态语法
初学者常范的错误是字面量语法传递数值
<!-- 传递了一个字符串 "1" -->
<comp some-prop="1"></comp>
因为它是一个字面量 prop,它的值是字符串 "1"
而不是一个数值。如果想传递一个真正的 JavaScript 数值,则需要使用 v-bind
,从而让它的值被当作 JavaScript 表达式计算:
<!-- 传递真正的数值 -->
<comp v-bind:some-prop="1"></comp>