性能优化:import动态加载组件

217 阅读2分钟

背景

在实际开发中,封装组件是一个常见需求,尤其是在处理灵活配置的场景时。比如,一个通用表单组件需要支持动态配置表单项,并需要配置配置数据引入不同类型组件,包括自定义组件。这样的需求需要设计低耦合、高灵活性的方案。

示例场景

假设我们有一个通用表单组件 CForm,通过 config 配置表单项:

<CForm :config="config" />

const config = [
    { component: 'el-input', label: '名称', key: 'name' },
    { component: 'myComponent', label: '自定义组件', key: 'custom' },
];

config 数组的每一项代表一个表单字段,其中 component 指定了要渲染的组件名称。然而,这种实现方式有一个 潜在问题

  • Vue 项目通常使用插件(unplugin-vue-components)实现按需引入。
  • 这种方式在编译时会根据使用的组件进行打包,但运行时无法解析通过字符串形式指定的组件名称。
  • 在组件内部使用 import 静态导入可能被使用到的组件是可行的,但如果运行时并未实际使用这些组件,每次使用 CForm 时,依赖的静态导入组件仍会被加载进来。这会导致资源浪费,并增加页面的初始加载时间

为了解决这个问题,通过 import 动态加载组件。

动态加载

CForm 组件内部

<template>
    <div v-for="item of props.config">
        <component :is="item.component" />
    </div>
</template>

const checkComp = () => {
   let components = props.config.map(x => x.component)
   for (let com of components){
       import(./../components/${com}.vue).then((module) => {
          // 这里可以给组件命名,这个技巧可以用在动态路由需要缓存,但是不想每个页面组件命名上。
          // 因为通常接口返回菜单和对应的页面组件。
          
       })
   }
}
// config数据变动。 不用担心会重复加载,因为加载的模块浏览器会进行缓存。
watch(() => props.config,() => {
    checkComp()
})

总结

动态加载组件的实现

利用 import() 方法,在运行时根据组件名称动态加载模块。

ES Module缓存机制 import() 加载的模块会被浏览器缓存,即使多次加载相同路径,也不会重复发起请求。这一特性可以有效避免性能开销。
也可以内部维护一个加载过的组件的map,判断是否加载过再决定是否import

动态渲染组件

使用 Vue 提供的 <component> 标签,结合 :is 动态绑定属性,将已加载的组件进行渲染。