组件
什么是组件?
组件是Vue最强大的功能之一.它们可以帮助你扩展基础的HTML元素,封装为可重用的代码.在较高层面上,组件是经过Vue编译后赋予了一些额外特性的自定义元素.在一些情况下,组件也可以是原生HTML元素的形式,以特殊的is
属性扩展.
使用组件
注册
之前已经学过创建一个vue实例的方式:
new Vue({
el: '#some-element',
// options
})
注册成全局组件,我们可以使用Vue.component(tagName, options)
.例如:
Vue.component('my-component', {
// options
})
注意:对于自定义元素标签名,Vue不强制要求遵循 W3C 规则(小写,并且包含一个'-'连字符),尽管遵循这个规则比较好。
一但注册后,组件便可以作为一个自定义元素在实例模板中使用(<my-component></my-component>
).但要确保在初始化根实例之前注册该组件,以下是完整例子:
<div id="example">
<my-component></my-component>
</div>
// register
Vue.component('my-component', {
template: '<div>A custom component!</div>'
})
// create a root instance
new Vue({
el: '#example'
})
最终会渲染成:
<div id="example">
<div>A custom component!</div>
</div>
局部注册
不必在全局注册每个组件.可以通过使用组件实例选项进行注册,使组件仅在另一个实例/组件的作用域中可用(父组件):
var Child = {
template: '<div>A custom component!</div>'
}
new Vue({
// ...
components: {
// <my-component> will only be available in parent's template
'my-component': Child
}
})
这种封装也适用于其它可注册的 Vue 功能,如指令。
DOM模板解析说明
当使用DOM作为模板时(例如用el
选项来挂载将要展示的内容),你将会受到一些HTML固有的限制,因为Vue只有在浏览器正确解析HTML的前提下才能获取模板内容.
尤其是像<ul>
,<ol>
,<table>
,<select>
这些只能出现在指定元素内部的标签. 比如<option>
只能出现在其它元素内部.
当在自定义元素中使用这些带有限制的元素很可能就会导致问题,比如:
<table>
<my-row>...</my-row>
</table>
自定义组件<my-row>被认为是无效的内容,会导致最终的渲染结果出错.当然,Vue提供了一个is
的特殊属性(前面有提到)作为变动的方案。
<table>
<tr is="my-row"></tr>
</table>
需要注意的是,如果使用以下几种字符串模板的来源,则不会有上述限制:
-
<script type="text/x-template">
-
JavaScript内联模版字符串
-
.vue 组件
所以还是推荐尽量使用上述几种方式😃
data 必须是函数
大多数能用在Vue构造器中的选项(options)也适用于component(组件)注册中,除了一个例外情况,那就是Data必须是一个函数,而不是一个键值对数据对象. 实际上,如果你尝试以下代码:
Vue.component('my-component', {
template: '<span>{{ message }}</span>',
data: {
message: 'hello'
}
})
Vue会直接中断执行并在控制台弹出警告--组件实例的data
属性必须是一个函数.我们通过以下几个小例子来理解Vue中为什么会有这个规则限制:
<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 , 因此每增加一次计数会影响所有组件!我们可以通过为每个组件返回新的 data 对象来解决这个问题:
data: function () {
return {
counter: 0
}
}
现在每个 counter 都有它自己内部的状态了:
构造组件
组件意味着协同工作,最常见的父子组件的关系中:组件A会在其模板中使用组件B.“老子和儿子”之间不可避免的需要相互通信。父组件需要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件。然而,通过定义良好的接口尽可能保持父子组件解耦是非常重要的。这保证了每个组件的代码可以在相对隔离的环境中编写和理解,从而使它们变得更具可维护性和可重用性。
在vue.js中,父子组件的关系可以概括为props down, events up.父组件通过props向下传递数据给子组件,子组件通过events给父组件发送消息。
让我们看下它们是如何工作的: