【Vue3从零开始-第三章】3-1 vue的局部组件和全局组件

334 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情

前言

第一章和第二章的文章中,我们了解了vue的很多基础知识,还有很多指令、方法、生命周期。在第三章正式开始学习之前,应该让大家更深的了解一下vue的组件概念,让大家不仅要会写vue代码,还要知道其中的概念,这样就可以更好的理解之后的内容了。

组件的概念

Snipaste_2022-04-16_21-28-14.jpg

组件就是把一个大的页面,拆分成一个一个小的页面,再把一个一个小的页面进行拆分。最终把一个一个的小组件连接起来,拼成一个大的页面然后渲染出来。

在第一章中我们做过组件的小例子,使用createApp方法创建出来的是一个vue应用,它也是页面中的根组件,在根组件中不管写什么样的模板,都只是一个组件而已。

<script>
  const app = Vue.createApp({
      template: `
          <div>
            <div>Hello</div>
            <div>World</div>  
          </div>
        `
  });
  const vm = app.mount('#root');
</script>

当页面中的元素越来越多之后,一个页面的代码就会显得很臃肿,那我们就应该把其中某些部分给拆分出来,单独用组件代码去维护。

下面我们可以把根组件中的HelloWorld两个组件都拆出来看看效果。

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

image.png

  • 通过component方法定义两个子组件helloworld,然后在根组件中去调用这两个子组件,这样就可以把页面中复杂的内容拆分出去,更大的减少了项目维护成本。

  • 在根组件中通过引用子组件的标签方式,把根组件和子组件进行一个关联,就可以在页面上将根组件和子组件都很好的渲染出来。

复用组件

组件除了可以拆分出来进行单独的维护之外,还有一个特性就是组件复用性,也就是某一个组件可以被反复的使用。

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

chrome-capture.gif

当我们把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>

chrome-capture (1).gif

  • 在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>

image.png

但是这样写完之后,不能直接在根组件中使用组件标签是因为我们只是把子组件写好了,并没有在根组件中引用进去。

const app = Vue.createApp({
    components: {
      counter: counter
    },
    template: `
      <div>
        <counter />
      </div>
    `
});
  • 只需要在根组件中定义一个components对象,对象中引用子组件标签名。

  • components对象中的key表示当前组件中使用的标签名,value表示子组件的名称。

  • 如果标签名和子组件的名称一致,可以简写成components: {counter}

image.png

当组件定义完成,并且也在根组件中引用之后,发现页面上还是会报错初始化时没有找到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>

chrome-capture (2).gif

此时页面上就可以正常渲染根组件和子组件的内容了。

局部组件映射

在全局组件中定义组件名称时,我们使用的是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>

chrome-capture (3).gif

这时候我们在components对象中映射组件的时候,就可以使用hello-world这种写法定义key,用首字母大写的方式定义value

但是在vue里面对于这种-间隔的局部组件写法也有另外一种映射关系。

const app = Vue.createApp({
    components: {
      Counter,
      HelloWorld
    },
    template: `
      <div>
        <hello-world />
        <counter />
      </div>
    `
  });
  • 可以直接在components对象里面直接用首字母大写的方式定义,在页面中采用-间隔的方式渲染标签。

弊端:局部组件定义之后,需要使用components对象注册到对应根组件中才能使用,虽然性能比较高,但是使用起来比较麻烦。

定义:局部组件在使用时,要做一个名字和组件之间的映射对象components,当你不写映射的时候,vue底层也会自动帮你做映射关系。

总结

在本篇文章中,我们讲解了组件的定义组件是具备复用性的全局组件局部组件