Vue 组件注册
我们先来看一下什么是组件:
Vue.js的组件就是提高重用性的,让代码可复用。
下面是一个Vue组件的示例,现在可以不用理解下面的代码:
<div id="app">
<hi></hi>
</div>
<script>
Vue.component("hi", {
data: function () {
return {
hello: "你好!"
}
},
template: "<div>{{hello}}</div>"
});
var app = new Vue({
el: "#app",
})
</script>
<hi>就是自定义的标签,一个自定义的标签就是一个组件。最后<hi>标签会被替换为template中定义的模板内容。
渲染结果为:
<div id="app">
<div>你好!</div>
</div>
可以将组件进行任意次的复用:
<div id="app">
<hi></hi>
<hi></hi>
<hi></hi>
</div>
渲染结果为:
<div id="app">
<div>你好!</div>
<div>你好!</div>
<div>你好!</div>
</div>
了解组件的内容,先从组件的注册开始。
(1)组件的注册
组件需要注册之后才可以使用。有两种组件注册的方法:全局注册和局部注册。
1.全局注册
全局注册的组件在注册之后可以用在任何新建的Vue根实例的模板中,比如:
<div id="app">
<test1></test1>
<test2></test2>
<test3></test3>
<test4></test4>
</div>
<script>
Vue.component('test1', {});
Vue.component('test2', {});
Vue.component('test3', {});
Vue.component('test4', {});
var app = new Vue({
el: "#app",
})
</script>
这几个组件在各自内部也都可以相互使用。
2.局部注册
可以在Vue实例中使用components选项来注册局部组件,注册后的组件只有在该实例作用域下有效。
<div id="app">
<hello></hello>
</div>
<script>
var aaa= {
template: `
<div>你好!</div>
`
};
var app = new Vue({
el: "#app",
components: {
'hello':aaa
}
})
</script>
渲染的结果为:
<div id="app">
<div>你好!</div>
</div>
对于components属性,属性名就是自定义组件的名字,属性值就是这个组件的选项对象。
3.组件名
在注册组件的时候,需要给组件一个名字,以便以后使用。
Vue.component('test', {
//some code
});
这里的"test"就是组件的名字,作为Vue.component的第一个参数。
定义组件名的方式有两种:
A.短横线分割命名(kebab-case)
Vue.component('my-component-name', {
//some code
});
当使用短横线分割命名法来定义一个组件的时候,在引用这个组件的时候也必须使用短横线分割命名的名字,即<my-component-name>。
B.驼峰式命名(PascalCase)
Vue.component('MyComponentName', {
//some code
});
当使用驼峰式命名法来定义一个组件的时候,在引用这个组件的时候使用两种命名法命名的名字都可以,<my-component-name>或者<MyComponentName>。
但是要注意的是,HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着,使用 DOM 中的模板时(非字符串模板),camelCase (驼峰命名法) 的命名需要使用其等价的 kebab-case (短横线分隔命名) 命名。
也就是说,在非字符串模板中使用时,只有短横线分割命名是有效的。
下面我们来看一下,什么是字符串模板,什么是非字符串模板:
字符串模板指的是在组件选项里用 template:"" 指定的模板,比如:
<div id="app">
<an></an>
</div>
<script>
Vue.component('an', {
template: `
<div>
<TestCan>
</TestCan>
</div>
`
});
Vue.component('TestCan', {
template: `
<div>
你好!
</div>
`
});
var app = new Vue({
el: "#app",
})
</script>
在注册组件<an>的时候,在template中使用了 <TestCan>,这种写法是没有问题的,最后可以成功渲染:
<div id="app">
<div>
<div>你好!</div>
</div>
</div>
非字符串模板,也就是DOM模板,指的是原本就写在页面上的内容,能被浏览器识别的html结构,会一加载就被浏览器渲染。
主要是下面这两种情况:
A.利用template标签来实现内容的填充,最终通过id挂载到template上面:
<div id="app">
<test></test>
</div>
<template id="template">
<div>
<TestCan></TestCan>
<h1>我是非字符串模板!</h1>
</div>
</template>
<script>
Vue.component('TestCan', {
template: `
<div>
你好!
</div>
`
});
Vue.component("test", {
template: "#template"
});
var app = new Vue({
el: "#app",
})
</script>
在<template id=“template”></template>中使用驼峰命名法,是会报错的:
HTML 中的特性名是大小写不敏感的,浏览器会把所有TestCan解释为testcan,会认为testcan组件没有注册。
换用短横线分隔命名法就可以正确渲染:
<div id="app">
<test></test>
</div>
<template id="template">
<div>
<test-can></test-can>
<h1>我是非字符串模板!</h1>
</div>
</template>
<script>
Vue.component('TestCan', {
template: `
<div>
你好!
</div>
`
});
Vue.component("test", {
template: "#template"
});
var app = new Vue({
el: "#app",
})
</script>
渲染结果为:
<div id="app">
<div>
<div>
你好!
</div>
<h1>我是非字符串模板!</h1>
</div>
</div>
B.内联模板:在使用组件时,给组件标签使用inline-template特性,组件就会把它的内容当作模板,例如:
<div id="app">
<test inline-template>
<div>
<test-can></test-can>
<div>{{msg}}</div>
</div>
</test>
</div>
<script>
Vue.component('TestCan', {
template: `
<div>
你好!
</div>
`
});
Vue.component("test", {
data: function () {
return {
msg: "我来自子组件!"
}
}
});
var app = new Vue({
el: "#app",
})
</script>
对于上面的代码,有以下几点需要注意:
1.内联模板可以使用子组件中声名的数据(这里是msg)
2.只能有一个根元素,如上面代码,把节点包裹在一个<div>中
3.驼峰式命名的组件名称要换用短横线分隔命名的名称
另外一种模板的写法
改变script中的type变为type=“text/x-template”,并且给它id,最终挂载到template中。
放在type=”text/x-template”中的内容将不会被浏览器解析,不被执行,不被显示。
因为不会被浏览器解析,所以不会涉及到浏览器会把所有大写字符解释为小写字符的问题。所以,这样的模板写法,采用驼峰式命名也可以正确渲染:
<div id="app">
<test></test>
</div>
<script type="text/x-template" id="template">
<div>
<TestCan></TestCan>
<h1>我是非字符串模板!</h1>
</div>
</script>
<script>
Vue.component('TestCan', {
template: `
<div>
你好!
</div>
`
});
Vue.component("test", {
template: "#template"
});
var app = new Vue({
el: "#app",
})
</script>
<div id="app">
<test></test>
</div>
<script type="text/x-template" id="template">
<div>
<test-can></test-can>
<h1>我是非字符串模板!</h1>
</div>
</script>
<script>
Vue.component('TestCan', {
template: `
<div>
你好!
</div>
`
});
Vue.component("test", {
template: "#template"
});
var app = new Vue({
el: "#app",
})
</script>
两种写法都可以正确渲染:
<div id="app">
<div>
<div>
你好!
</div>
<h1>我是非字符串模板!</h1>
</div>
</div>
(2)组件选项中的template
在上面注册组件的时候,用到了template,template用来定义组件的内容。
下面代码中,最后自定义标签<hi>会被替换为template中定义的模板内容。
<div id="app">
<hi></hi>
</div>
<script>
Vue.component("hi", {
template: "<div>你好!</div>"
});
var app = new Vue({
el: "#app",
})
</script>
渲染结果为:
<div id="app">
<div>你好!</div>
</div>
要注意的是,template的DOM结构必须被一个元素包含,直接在template中写文字是不会被渲染的。
只能有单个根元素
如下编写模板会报错:
Vue.component('test', {
template: `
<div>1</div>
<div>2</div>
`
});
因为在模板中出现了两个根元素,两个<div>。
为了解决这个问题,可以将它们包裹在一个父元素中。
Vue.component('test', {
template: `
<div>
<div>1</div>
<div>2</div>
</div>
`
});
(3)组件选项中的data必须是一个函数
组件是可复用的Vue实例,它们可以与new Vue接收相同的选项,例如:data、computed、watch、methods以及生命周期钩子函数等。但是像el这样的根实例特有的选项是不能接收的。对于data选项需要注意的是:
一个组件的 data 选项必须是一个函数:
<div id="app">
<hi></hi>
</div>
<script>
Vue.component("hi", {
data: function () {
return {
hello: "你好!"
}
},
template: "<div>{{hello}}</div>"
});
var app = new Vue({
el: "#app",
})
</script>
在javascript中对象是引用关系,如果return的对象引用了一个外部对象,那么这个对象就是共享的,任何一方的修改都会同步:
<div id="app">
<counter></counter>
<counter></counter>
<counter></counter>
</div>
<script>
var data = {
count: 0
};
Vue.component("counter", {
data: function () {
return data
},
template: "<button v-on:click='count++'>{{count}}</button>"
});
var app = new Vue({
el: "#app",
})
</script>
点击任何一个按钮都会使得count增加1。
修改一下代码,组件返回一个新的data对象,每个实例就有一个返回对象的独立的拷贝:
<div id="app">
<counter></counter>
<counter></counter>
<counter></counter>
</div>
<script>
Vue.component("counter", {
data: function () {
return {
count: 0
}
},
template: "<button v-on:click='count++'>{{count}}</button>"
});
var app = new Vue({
el: "#app",
})
</script>
这样三个按钮就互不影响,相互独立了。
参考:
1.Vue.js官方文档
2.《Vue.js实战》