Vue 组件规范
命名约定
对于组件的命名,W3C规范是字母小写且包含一个中划线(-),虽然Vue没有强制要求,但最好遵循规范。
<!-- 在HTML模版中始终使用 kebab-case --> <kebab-cased-component></kebab-cased-component> <camel-cased-component></camel-cased-component> <pascal-cased-component></pascal-cased-component>
// 当注册组件时,使用中划线、小驼峰、大驼峰这三种任意一种都可以。
// 在组件定义中
components: {
// 使用 中划线 形式注册
'kebab-cased-component': { /* ... */ },
// 使用 小驼峰 形式注册
'camelCasedComponent': { /* ... */ },
// 使用 大驼峰 形式注册
'PascalCasedComponent': { /* ... */ }
}
解析DOM模板时的注意事项 — 嵌套限制
有些 HTML 元素,诸如 <ul>、<ol>、<table>和 <select>,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li>、<tr>和 <option>,只能出现在其它某些特定的元素内部。
这会导致我们在自定义组件中使用这些有约束条件的元素时遇到一些问题。例如:
<table> <blog-post-row></blog-post-row> </table>
这个自定义组件 <blog-post-row>会被作为无效的内容提升到外部,并导致最终渲染结果出错。
[ is 特性 ]幸好这个特殊的 is特性给了我们一个变通的办法:
<table id="example">
<tr is="my-row"></tr>
</table>
<script>
// 注册
var header = {
template: '<div class="hd">我是标题</div>'
};
// 创建实例
new Vue({
el: '#example',
components: {
'my-row': header
}
})
</script>
需要注意的是如果我们从以下来源使用模板的话,这条限制是不存在的:
- 字符串 (例如:
template: '...')- 单文件组件 (
.vue)<script type="text/x-template">
根元素
Vue强制要求每一个Vue实例 ( 组件本质上就是一个Vue实例 ) 需要有一个根元素。
如下所示,则会报错:
<div id="example">
<my-component></my-component>
</div>
<script>
// 注册
Vue.component('my-component', {
template: `
<p>第一段</p>
<p>第二段</p>
`,
})
// 创建根实例
new Vue({
el: '#example'
})
</script>
需要改写成如下所示:
<script>
// 注册
Vue.component('my-component', {
template: `
<div>
<p>第一段</p>
<p>第二段</p>
</div>
`,
})
// 创建根实例
new Vue({
el: '#example'
})
</script>
data数据
一般地,我们在Vue实例对象或Vue组件对象中,我们通过data来传递数据。
<div id="example">
<my-component></my-component>
<my-component></my-component>
<my-component></my-component>
</div>
<script>
// 注册
Vue.component('my-component', {
template: '<div>{{message}}</div>',
data:{
message: 'hello'
}
})
// 创建根实例
new Vue({
el: '#example'
})
</script>
运行上面的代码,会使Vue停止执行,并在控制台发出错误提示,告诉你在组件中 data 必须是一个函数。
可以用如下方式来绕开Vue的错误提示:
<script>
// 注册
var data = {counter: 0}
Vue.component('my-component', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
data:function(){
return data;
}
})
// 创建根实例
new Vue({
el: '#example'
})
</script>
由于这三个组件共享了同一个 data,因此增加一个 counter 会影响所有组件
当一个组件被定义, data 需要声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象。通过提供 data 函数,每次创建一个新实例后,能够调用 data 函数,从而返回初始数据的一个全新副本数据对象
因此,可以通过为每个组件返回全新的 data 对象来解决这个问题:
<script>
// 注册
Vue.component('my-component', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
data:function(){
return {counter: 0};
}
})
// 创建根实例
new Vue({
el: '#example'
})
</script>
// 现在每个 counter 都有它自己内部的状态了
原生事件
有时候,可能想在某个组件的根元素上监听一个原生事件。直接使用v-bind指令是不生效的。
<div id="example">
<my-component @click="doTheThing"></my-component>
<p>{{message}}</p>
</div>
<script>
Vue.component('my-component', {
template: '<button>按钮</button>',
})
new Vue({
el: '#example',
data:{
message:0
},
methods:{
doTheThing(){
this.message++;
}
}
})
</script>
// 可以使用 .native 修饰 v-on指令即可。
<div id="example">
<my-component @click.native="doTheThing"></my-component>
<p>{{message}}</p>
</div>
<script>
Vue.component('my-component', {
template: '<button>按钮</button>',
})
new Vue({
el: '#example',
data:{
message:0
},
methods:{
doTheThing(){
this.message++;
}
}
})
</script>