04-手写一个组件

Catalogue
  1. 1. 组件名
  2. 2. 注册全局组件
  3. 3. 注册局部组件
  4. 4. 参考资料

组件名

在注册一个组件的时候,我们始终需要给它一个名字。

  1. 使用 kebab-case

当使用 kebab-case (短横线分隔命名) 定义一个组件时,你也必须在引用这个自定义元素时使用 kebab-case,例如 my-component-name。

  1. 使用 PascalCase

当使用 PascalCase (首字母大写命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。也就是说 my-component-name 和 MyComponentName都是可接受的。注意,尽管如此,直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的。

提一下什么是非字符串的模板?

字符串模板:指的是在组件选项里用 template:”” 指定的模板,换句话说,写在 js 中的 template:”” 中的就是字符串模板。比如下面这个:

1
2
3
var tmp = new Vue({
template:"<myComponent></myComponent>"
});

非字符串模板:在单文件*.vue里用 指定的模板,换句话说,写在 html 中的就是非字符串模板。

注册全局组件

1
2
3
4
5
6
7
8
9
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:

1
2
3
4
5
<div id="components-demo">
<button-counter></button-counter>
</div>

new Vue({ el: '#components-demo' })

注意点:

  1. 因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。
  2. data 必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝,不然多个组件间修改data值时会影响其他组件。
  3. 全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。也就是说这三个组件在各自内部也都可以相互使用。

注册局部组件

全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。

在这些情况下,你可以通过一个普通的 JavaScript 对象来定义组件,该对象类似于Vue.component的第2个参数对象,也是一个Vue实例。

1
2
3
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }

然后在 components 选项中定义你想要使用的组件:

1
2
3
4
5
6
7
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})

对于 components 对象中的每个属性来说,其属性名就是自定义元素的名字,其属性值就是这个组件的选项对象。

如果使用了webpack,则建议创建一个 components 目录,并将每个组件放置在其各自的文件中。然后你需要在局部注册之前导入每个你想使用的组件。例如,在一个假设的 ComponentB.jsComponentB.vue 文件中导入ComponentA、ComponentC组件:

1
2
3
4
5
6
7
8
9
10
11

import ComponentA from './ComponentA'
import ComponentC from './ComponentC'

export default {
components: {
ComponentA,
ComponentC
},
// ...
}

注意点:

  1. 注意局部注册的组件在其子组件中不可用。例如,如果你希望 ComponentA 在 ComponentB 中可用,则你需要这样写:
1
2
3
4
5
6
7
8
var ComponentA = { /* ... */ }

var ComponentB = {
components: {
'component-a': ComponentA
},
// ...
}

或者如果你通过 Babel 和 webpack 使用 ES2015 模块,那么代码看起来更像:

1
2
3
4
5
6
7
8
import ComponentA from './ComponentA.vue'

export default {
components: {
ComponentA
},
// ...
}

注意在 ES2015+ 中,在对象中放一个类似 ComponentA 的变量名其实是 ComponentA: ComponentA 的缩写,即这个变量名同时是:

  • 用在模板中的自定义元素的名称
  • 包含了这个组件选项的变量名

参考资料