vue的动态组件-component

14,491 阅读4分钟

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


一、什么是动态组件

学习动态组件之前,我们需要知道什么是组件。

对于组件官方是这样定义的:组件是可复用的 Vue 实例。就是说,组件也是Vue实例,但是组件和vue实例也有差异:

1. 组件没有挂载目标 el ,因为组件是跟着vue实例的,所有vue实例的挂载点也是组件的挂载点2. 组件中data不能是对象,因为vue实例是单例模式,只有一个,组件有多个。我们知道多个属性调用对象会指向统一地址,但是方法每new一个实例就会开辟一块新的内存空间。所以组件中不能是对象,必须是方法。

而动态组件就是动态变化的组件,和动态样式一样,通过用户的操作来确定是什么类型的组件。

动态样式是绑定:style,动态组件则是绑定:is

二、动态组件的具体实现

使用场景:需要的组件不确定时,可以使用动态组件的方式生成。例如:接收到一个文本数据,我们就动态生成一个文本组件。接收到一个图片数据,我们就动态生成一个图片组件。

实现思路:

  1. 首先需要定义json数据,每一项键值对存储类型数据

    这里的json数据主要是用来存储组件类型,可以存储多个组件类型,为了方便我们就让它的type对应组件的名称。

    这里的json数据采用默认导出的方法export default,一个文件只有一个方法时就用默认导出

    export default = [{    id:1,    type:'textComp'},{    id:2,    type:'imageComp'}]
    
    1. 导入json数据,将数据存入data中

      导入默认导出的js文件,不需要{}来接收。

      因为我导入文件时经常忘记要不要{},所以这里复习一下导入的知识点:默认导入不需要{},命名导入需要{}

      ​ ​
    2. 创建需要渲染的组件模板(TextCompImageComp

      封装组件的时候尽量设置规范的name值(我之前喜欢小驼峰命名,但是不符合官方规范)。

      我们在设置组件名时一定要遵守Vue给出的官方命名规范:要么始终字母开头大写,要么始终单词之间横线连接。例子:

      反例:mycomponent.vuemyComponent.vue。好例子:MyComponent.vuemy-component.vue

      ​ ​
    3. 引入所有组件模板

      这里也是使用默认导入组件,因为组件内中script使用的导出方法为默认导出

  2. 利用动态组件的标签,动态绑定is,渲染指定组件(本来可以变成,依靠is来动态绑定样式)

补充知识:

关于内置组件 component 的使用。这里参考一下Vue官方的说明:

#compoent

  • Props:

  • is: string | ComponentDefinition | ComponentConstructor

  • inline-template:boolean

  • 用法:

渲染一个“元组件”为动态组件。依is的值,来决定哪个组件被渲染

 //动态组件由 vm 实例的 `componentId` proterty实例 
<component :is='componentId'></component>
​ //也能够渲染注册过的组件或 prop 传入的组件
 <component :is='$options.components.child'><component>

总结:component可以通过is动态渲染不同的组件

<template>
    <div id='app'>
        <component :is='textCompName'></component>
    </div>
</template><script>import textComp from './components/TextComp'data(){
    return{
        textCompName:'TextComp'
    }
}
</script>
  1. 通过json数据,动态渲染指定组件

这里通过导入的json数据,通过v-for遍历json中每一项的type,通过type动态设置component中的:is,从而生成动态组件

如果json数据中的type与组件名不同时,就要通过计算属性,遍历获取到dataList的每一项并读取type值。动态组件标签的is绑定计算属性,由于是数组对象,可以使用v-for

<template>
    <div id='app'>
        <div v-for='item in getCompType' :key='item.id'>
            <component :is='item.type'></component>
        </div>
    </div>
</template><script>
    computed:{
        getCompType(){
            return this.dataList.forEach(item=>{
                return {
                    ...item,
                    type:item.type+'Comp'
                }
            })
        }
    }
</script>​​

<template>
  <div id="app">
    <div v-for="item in dataList" //这里组件名和json中的type相同也可以直接使用
         :key="item.id">
      <component :is="item.type">
</component>
    </div>
  </div>
</template>

简单说一下Array.prototype.map()Array.prototype.forEach()的区别

forEach()不返回执行结果,返回undefinedforEach()被调用,不改变原数组

map()会产生新数组,并分配内存空间存储,并且不会修改原数组

完整代码:

TextComp.vue`
<template>
  <div>文本组件模板</div>
</template><script>
export default {​}
</script>
ImageComp.vue
<template>
  <div>图片组件模板</div>
</template><script>
export default {​}
</script><style></style>
dataList.js
module.exports = [{
    id: 1,
    type: 'TextComp'
  },
  {
    id: 2,
    type: 'ImageComp'
  }]
App.vue
<template>
  <div id="app">
    <div v-for="item in dataList"
         :key="item.id">
      <component :is="item.type"></component>
    </div>
  </div>
</template><script>
import dataList from './data/dataList.js'
import imageComp from './components/ImageComp'
import textComp from './components/TextComp'
export default {
  name: 'App',
  data () {
    return {
      // 根据传入的json来实现组件动态绑定,前提是json中存在type且和组件名相同
      dataList,
      // 动态绑定 imageComp 组件,但是这里是写死的,我们需要根据传入的json数据来动态绑定组件
      // componentId: ImageComp​
    }
  },
  components: {
    ImageComp,
    TextComp
  }
}
</script>

效果展示:

补充知识:组件化与模块化的区别

相同点:都是为实现代码的高内聚、低耦合、提高复用率

不同点:

  1. 组件是一段代码集,包括htmlcssjsimage;模块指的是js代码。

  2. 组件是封装一个功能;模块封装的是一个方法

模块和模块化、组件和组件化的区别:使用了组件化的形式编程就叫组件化

总结:

通过学习Vue动态组件,加深了我对vue组件化的理解。也更清楚了组件化与模块化的区别

组件化是Vue的精髓,Vue应用就是通过一个个组件构成的。

组件化有点类似与js中的模块化,同样是提高了代码复用。