likes
comments
collection
share

全局组件&局部组件

作者站长头像
站长
· 阅读数 17

组件的定义

组件就是页面中的一部分

一个网页可以被拆分成很多部分,如下图所示,可以被拆分成头部、左侧和右侧是三个部分。每个部分又可以进一步的做出细分,如左侧可以细分成2个部分,右侧可以被拆成3个部分。这样就可以抽象成树状的结构,最顶层的树的根节点相当于整个网页,接着又被拆成3个子组件...,由此就构成了页面和树状结构的对应关系。很多小的组件实际上就是页面中的一部分,把它们层层的拼装,最终就拼成完整的网页,这就是组件被设计的理念,把一个复杂的网页拆成很多小的部分(组件)进行维护

全局组件&局部组件

组件的拆分

  const app = Vue.createApp({})
  const vm = app.mount('#root')

通过Vue.createApp创建的不是组件而是一个vue实例/应用,创建实例的时候会接收一个对象作为参数,而这个参数就会决定vue的根组件如何的被渲染,对应上图右侧树状结构中的根组件

如果我们只写了一个根组件,就相当于上图树状图中到根组件就结束了,就没有下面的子组件了

那么如果我们想对组件进行进一步的拆分,就需要定义子组件,如何定义子组件呢?

拆分子组件前

const app = Vue.createApp({
    template:'<div>hello</div><div>world</div>'
})
const vm = app.mount('#root')

如果页面越来越复杂,template中的代码越来越多,如果想把<div>hello</div><div>world</div>这2个区域拆分成组件单独维护呢?

拆分子组件后

  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')
  

我们发现运行的结果还是一样

全局组件&局部组件

但是此时页面的组织结构就发生了变化,之前只有一个根组件,现在根组件下面有2个子组件了,如下图所示

全局组件&局部组件

接着将2个子组件同根组件建立关系,根组件调用2个子组件,那么就把一个复杂的页面拆成几个部分进行维护,这样整个页面的维护成本就得到了有效的降低

组件具有复用性且组件中的数据被组件『独享』

组件除了本身作为页面的一部分之外,还有一定的复用性

const app = Vue.createApp({
    template:`
    <div>
        <counter/>
        <counter/>
        <counter/>
    <div/>
    `
})
app.component('counter',{
    data(){
        return {
            counter: 0
        }
    },
    template: '<div @click="counter += 1">{{counter}}</div>'
})

const vm = app.mount('#root')

全局组件&局部组件

如上面所示,定义了一个计数器组件,在根组件中多次调用,就达到了复用组件的目的,且组件之间彼此独立运作,自己有自己的数据,互不干扰,每次点击,它只会给自己的数据进行+1

全局组件

再定义一个组件 <counter-parent/>,在这个组件中使用counter组件试试

const app = Vue.createApp({
    template:`
    <div>
        <counter-parent/>
        <counter/>
        <counter/>
        <counter/>
    <div/>
    `
})
app.component('counter-parent',{
    template:`<counter/>`
})
app.component('counter',{
    data(){
        return {
            counter: 0
        }
    },
    template: '<div @click="counter += 1">{{counter}}</div>'
})

const vm = app.mount('#root')

全局组件&局部组件

由此可知,当使用app.component的方式定义一个组件时,父组件中(这里是根组件)可以直接使用这个组件(<counter/>组件),子组件中(<counter-parent/>子组件)也可以使用这个组件(<counter/>子组件)

也就是说,app.component定义的组件是一个全局组件,在任何地方都可以使用

定义全局组件的弊端:

如果定义了很多的全局组件,但是没有使用这些定义的全局组件,但是这些组件会一直挂在vue的实例上,它对性能是有一定程度的损耗的,但是只要定义了,处处随时可以使用

总 结

  1. 全局组件,只要定义了全局可以使用,性能不高,但是使用起来简单
  2. 名字建议:小写字母单词,中间横线间隔

局部组件

如何定义和使用局部组件

与全局组件想对应是局部组件,那么我们该如何定义一个局部组件呢?

const counter = {
    data(){
        return {
            counter: 0
        }
    },
    template: '<div @click="counter += 1">{{counter}}</div>'
}
const app = Vue.createApp({
    components:{
        counter: counter
    },
    template:`
    <div>
        <counter/>
    </div>
    `
})
const vm = app.mount('#root')

我们直接定义的counter对象就是一个局部组件,但是定义完的局部组件并不能被立即使用。在vue的实例中使用这个组件是不行的,因为它感知不到这个局部组件的存在,局部组件不会像全局组件那样直接挂到vue的实例上,它就只是一个常量

我们需要在vue中使用components声明这个组件

  1. 使用Vue.createApp({...}) 创建了一个vue的实例
  2. 同时定义vue实例的根组件{...}
  3. 根组件中会使用一些局部组件components:{counter: counter},局部组件中有个叫counter的组件,它的对象的引用地址存在counter中,也就是说第前面的counter是调用组件时想称呼的组件名,后面的counter指的是定于过的局部组件本身,换句话前面的counter就是局部组件的名字

我们当然可以给它叫一个自己喜欢的名字,比如叫xxx吧

 const counter = {
    data(){
        return {
            counter: 0
        }
    },
    template: '<div @click="counter += 1">{{counter}}</div>'
}
const app = Vue.createApp({
    components:{
        xxx: counter
    },
    template:`
    <div>
        <xxx/>
    </div>
    `
})
const vm = app.mount('#root')

根据ES6中的语法,由于对象的key值和value值是一样的,因此我们也可以简写

const counter = {
    data(){
        return {
            counter: 0
        }
    },
    template: '<div @click="counter += 1">{{counter}}</div>'
}
const app = Vue.createApp({
    components:{
        counter
    },
    template:`
    <div>
        <counter/>
    </div>
    `
})
const vm = app.mount('#root')

再来看一个定义局部组件的例子吧

const counter = {
   data(){
       return {
           counter: 0
       }
   },
   template: '<div @click="counter += 1">{{counter}}</div>'
}
const helloWorld = {
   template:`<div>hello world</div>`
}
const app = Vue.createApp({
   components:{
       counter,
       'hello-world': helloWorld
   },
   template:`
   <div>
       <hello-world/>
       <counter/>
   </div>
   `
})
const vm = app.mount('#root')

局部组件的名字

前面定义全局组件给全局组件起名字的时候,app.component('counter-parent',{}),一般用-间隔的方式起名字,怎么定义局部组件的时候又用驼峰的方式?

如果局部组件也使用-的方式,那么定义局部组件时就const hello-world = {...} 显然这不是正确的声明变量的方式,因此只能使用驼峰命名的方式来命名局部组件

但是使用驼峰的命名又和普通的JS的变量没有区别,因此定义局部组件的时候,建议使用首字母大写的驼峰式

当然如果还是想在使用局部组件的时候使用小写,那么在实例中声明局部组件的时候就要重新做个名字和局部组件之间的映射

const Counter = {
    data(){
        return {
            counter: 0
        }
    },
    template: '<div @click="counter += 1">{{counter}}</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')

当然,即使我们不在vue实例中声明局部组件的时候,写局部组件的名字和局部组件之间的映射components,vue也会帮我们做这个映射,他会根据我们定义的局部的名字,同使用局部组件的名字时做个比较,并自动的做出映射

const Counter = {
    data(){
        return {
            counter: 0
        }
    },
    template: '<div @click="counter += 1">{{counter}}</div>'
}
const HelloWorld = {
    template:`<div>hello world</div>`
}
const app = Vue.createApp({
    components:{ Counter,HelloWorld },
    template:`
    <div>
        <hello-world/>
        <counter/>
    </div>
    `
})
const vm = app.mount('#root')

总结

  1. 局部组件,定义了,要注册后才能使用,使用起来麻烦,性能比较高,因为即使定义了不使用,它也不会一直挂在vue实例上,它就是一个变量
  2. 命名的时候建议大写字母开头,驼峰式命名
  3. 局部组件使用前,要做一个名字和组件间映射对象(componts),如果你不写,vue底层也会自动尝试帮你做这个映射