Vue.js学习 Item11 – 组件与组件间的通信

什么是组件?

组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展。

使用组件

注册

之前说过,我们可以用 Vue.extend() 创建一个组件构造器:

var MyComponent = Vue.extend({
  // 选项...
})
要把这个构造器用作组件,需要用 `Vue.component(tag, constructor)` **注册** :
// 全局注册组件,tag 为 my-component
Vue.component('my-component', MyComponent)

对于自定义标签名字,Vue.js 不强制要求遵循 W3C 规则(小写,并且包含一个短杠),尽管遵循这个规则比较好。

组件在注册之后,便可以在父实例的模块中以自定义元素 的形式使用。要确保在初始化根实例之前注册了组件:

<div id="example">
  <my-component>my-component>
div>
// 定义
var MyComponent = Vue.extend({
  template: '
A custom component!
'
}) // 注册 Vue.component('my-component', MyComponent) // 创建根实例 new Vue({ el: '#example' })
渲染为:
<div id="example">
  <div>A custom component!div>
div>

注意组件的模板替换了自定义元素,自定义元素的作用只是作为一个挂载点。可以用实例选项 replace 决定是否替换。

局部注册

不需要全局注册每个组件。可以让组件只能用在其它组件内,用实例选项 components 注册:

var Child = Vue.extend({ /* ... */ })

var Parent = Vue.extend({
  template: '...',
  components: {
    //  只能用在父组件模板内
    'my-component': Child
  }
})
这种封装也适用于其它资源,如指令、过滤器和过渡。

注册语法糖

为了让事件更简单,可以直接传入选项对象而不是构造器给 Vue.component()component 选项。Vue.js 在背后自动调用 Vue.extend()

// 在一个步骤中扩展与注册
Vue.component('my-component', {
  template: '
A custom component!
'
}) // 局部注册也可以这么做 var Parent = Vue.extend({ components: { 'my-component': { template: '
A custom component!
'
} } })

组件选项问题

传入 Vue 构造器的多数选项也可以用在 Vue.extend() 中,不过有两个特例: datael。试想如果我们简单地把一个对象作为 data 选项传给 Vue.extend()

var data = { a: 1 }
var MyComponent = Vue.extend({
  data: data
})
这么做的问题是 `MyComponent` 所有的实例将共享同一个 `data` 对象!这基本不是我们想要的,因此我们应当使用一个函数作为 `data` 选项,让这个函数返回一个新对象:
var MyComponent = Vue.extend({
  data: function () {
    return { a: 1 }
  }
})
同理,`el` 选项用在 `Vue.extend()` 中时也须是一个函数。

模板解析

Vue 的模板是 DOM 模板,使用浏览器原生的解析器而不是自己实现一个。相比字符串模板,DOM 模板有一些好处,但是也有问题,它必须是有效的 HTML 片段。一些 HTML 元素对什么元素可以放在它里面有限制。常见的限制:

  • a 不能包含其它的交互元素(如按钮,链接)
  • ulol 只能直接包含 li
  • select 只能包含 optionoptgroup
  • table 只能直接包含 thead, tbody, tfoot, tr, caption, col, colgroup
  • tr 只能直接包含 thtd

在实际中,这些限制会导致意外的结果。尽管在简单的情况下它可能可以工作,但是你不能依赖自定义组件在浏览器验证之前的展开结果。例如 不是有效的模板,即使 my-select 组件最终展开为

另一个结果是,自定义标签(包括自定义元素和特殊标签,如