一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情。
前言
在第一章和第二章的文章中,我们了解了vue的很多基础知识,还有很多指令、方法、生命周期。在第三章正式开始学习之前,应该让大家更深的了解一下vue的组件概念,让大家不仅要会写vue代码,还要知道其中的概念,这样就可以更好的理解之后的内容了。
组件的概念
组件就是把一个大的页面,拆分成一个一个小的页面,再把一个一个小的页面进行拆分。最终把一个一个的小组件连接起来,拼成一个大的页面然后渲染出来。
在第一章中我们做过组件的小例子,使用createApp方法创建出来的是一个vue应用,它也是页面中的根组件,在根组件中不管写什么样的模板,都只是一个组件而已。
<script>
const app = Vue.createApp({
template: `
<div>
<div>Hello</div>
<div>World</div>
</div>
`
});
const vm = app.mount('#root');
</script>
当页面中的元素越来越多之后,一个页面的代码就会显得很臃肿,那我们就应该把其中某些部分给拆分出来,单独用组件代码去维护。
下面我们可以把根组件中的Hello和World两个组件都拆出来看看效果。
<script>
const app = Vue.createApp({
template: `
<div>
<hello />
<world />
</div>
`
});
app.component('hello', {
template: `
<div>Hello</div>
`
})
app.component('world', {
template: `
<div>World</div>
`
})
const vm = app.mount('#root');
</script>
-
通过
component方法定义两个子组件hello和world,然后在根组件中去调用这两个子组件,这样就可以把页面中复杂的内容拆分出去,更大的减少了项目维护成本。 -
在根组件中通过引用子组件的标签方式,把根组件和子组件进行一个关联,就可以在页面上将根组件和子组件都很好的渲染出来。
复用组件
组件除了可以拆分出来进行单独的维护之外,还有一个特性就是组件复用性,也就是某一个组件可以被反复的使用。
<script>
const app = Vue.createApp({
template: `
<div>
<counter />
<counter />
<counter />
</div>
`
});
app.component('counter', {
data(){
return {
count: 1
}
},
template: `
<div @click="count += 1">{{count}}</div>
`
})
const vm = app.mount('#root');
</script>
当我们把counter组件复制多份之后,在页面上点击某个组件时,会发现组件和组件之间并没有互相影响,由此可知:
组件是可以被复用的,同时复用出来的每一个组件的数据都是独立的,而且只会处理自身的方法和事件。
全局组件
通过app.component创建的组件都是全局组件,而全局组件是可以在根组件和其他子组件中使用的。
<script>
const app = Vue.createApp({
template: `
<div>
<counter-parent />
<counter />
</div>
`
});
app.component('counter-parent', {
template: `
<counter />
`
})
app.component('counter', {
data(){
return {
count: 1
}
},
template: `
<div @click="count += 1">{{count}}</div>
`
})
const vm = app.mount('#root');
</script>
-
在vue实例下使用
app.component定义了一个counter-parent组件,这个组件属于根组件下面的子组件,在counter-parent组件中又引用了另外一个通过app.component定义的counter组件。 -
定义的这两个组件其实都是属于根组件下面的子组件,但是我们都是使用
app.component创建的,那么这两个组件就可以在任何地方去使用了。
弊端:当我们创建了全局组件之后,就算不在任何组件内使用,这个全局组件也会一直挂载在app上,会一直消耗vue的性能,所以一般不建议使用全局组件。
定义:全局组件只要定义了,不管是根组件还是子组件都可以使用,虽然使用简单但是性能不高。
局部组件
局部组件顾名思义就是仅在某个组件内部定义的组件,比如在根组件中定义的子组件只能在根组件中使用,在其他子组件中定义的孙子组件,只能在子组件中使用。
局部组件定义也很简单,直接创建一个对象,对象里面和全局组件类似,也可以定义vue里面的方法、模板等。
<script>
const app = Vue.createApp({
template: `
<div>
<counter />
</div>
`
});
const counter = {
data(){
return {
count: 1
}
},
template: `
<div @click="count += 1">{{count}}</div>
`
}
const vm = app.mount('#root');
</script>
但是这样写完之后,不能直接在根组件中使用组件标签是因为我们只是把子组件写好了,并没有在根组件中引用进去。
const app = Vue.createApp({
components: {
counter: counter
},
template: `
<div>
<counter />
</div>
`
});
-
只需要在根组件中定义一个
components对象,对象中引用子组件标签名。 -
components对象中的key表示当前组件中使用的标签名,value表示子组件的名称。 -
如果标签名和子组件的名称一致,可以简写成
components: {counter}
当组件定义完成,并且也在根组件中引用之后,发现页面上还是会报错初始化时没有找到counter组件,此时我们只需要在vue实例创建之前定义子组件就可以了。
<script>
const counter = {
data(){
return {
count: 1
}
},
template: `
<div @click="count += 1">{{count}}</div>
`
}
const app = Vue.createApp({
components: {
counter: counter
},
template: `
<div>
<counter />
</div>
`
});
const vm = app.mount('#root');
</script>
此时页面上就可以正常渲染根组件和子组件的内容了。
局部组件映射
在全局组件中定义组件名称时,我们使用的是counter-parent这样小写字母并用-间隔的,但是局部组件定义的是一个js常量,在常量中是不可以用-间隔的,而且当页面中的常量定义过多之后,会分不清哪些是组件,哪些是定义的常量值。
所以我们在定义局部组件的时候,应该采用首字母大写,多个单词使用驼峰方式。
<script>
const Counter = {
data(){
return {
count: 1
}
},
template: `
<div @click="count += 1">{{count}}</div>
`
}
const HelloWorld = {
template: `
<div>Hello World</div>
`
}
const app = Vue.createApp({
components: {
counter: Counter,
'hello-world': HelloWorld
},
template: `
<div>
<hello-world />
<counter />
</div>
`
});
const vm = app.mount('#root');
</script>
这时候我们在components对象中映射组件的时候,就可以使用hello-world这种写法定义key,用首字母大写的方式定义value。
但是在vue里面对于这种-间隔的局部组件写法也有另外一种映射关系。
const app = Vue.createApp({
components: {
Counter,
HelloWorld
},
template: `
<div>
<hello-world />
<counter />
</div>
`
});
- 可以直接在
components对象里面直接用首字母大写的方式定义,在页面中采用-间隔的方式渲染标签。
弊端:局部组件定义之后,需要使用
components对象注册到对应根组件中才能使用,虽然性能比较高,但是使用起来比较麻烦。
定义:局部组件在使用时,要做一个名字和组件之间的映射对象
components,当你不写映射的时候,vue底层也会自动帮你做映射关系。
总结
在本篇文章中,我们讲解了组件的定义、组件是具备复用性的、全局组件、局部组件。