前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【技术创作101训练营】三种不同场景下 vue 组件动态加载的方法及实现

【技术创作101训练营】三种不同场景下 vue 组件动态加载的方法及实现

原创
作者头像
CS逍遥剑仙
修改2020-09-23 13:18:23
2.8K0
修改2020-09-23 13:18:23
举报
文章被收录于专栏:禅林阆苑

Write By CS逍遥剑仙 我的主页: www.csxiaoyao.com GitHub: github.com/csxiaoyaojianxian Email: sunjianfeng@csxiaoyao.com

1. 背景

前端模块化开发模式已成主流,但随着前端项目规模的不断扩大,开发者可能会遇到以下一些问题:

  1. 不仅打包的效率越来越低下,而且打包后的文件体积也不断增加;
  2. 首屏加载文件过大,白屏时间过长;
  3. 有时,加载的组件名称不确定,需要动态确定需要加载的组件;
  4. 整体打包导致大型项目若需要扩展组件,开发者必须下载完整工程,被迫开放源码,且易冲突

本文将选用 vue 框架,使用三种方式实现前端模块的动态加载,分别解决上述的一个或多个问题。

2. vue 动态 & 异步组件

在大型应用中,我们常常需要将应用切分,在客户端请求时按需加载,减少首次请求的文件体积,并缓存供下次使用。vue 框架提供了动态组件 & 异步组件功能 ( 文档地址 )。

2.1 动态组件实现组件动态切换

动态组件即通过 is 属性来动态地切换不同的组件:

代码语言:txt
复制
<component v-bind:is="currentComponent"></component>

2.2 异步组件实现懒加载

而异步组件则允许以工厂函数的方式定义组件并异步解析,只有当该组件需要被渲染时才会触发该工厂函数,并缓存组件供下次使用:

代码语言:txt
复制
Vue.component(
  'async-example',
  () => import('./async-component') // 返回一个 Promise 对象
)

异步组件同样适用于组件的局部注册方式:

代码语言:txt
复制
new Vue({
  components: {
    'async-component': () => import('./async-component')
  }
})

2.3 动态 & 异步组件实现组件动态加载

结合动态组件和异步组件的特性,即可轻松实现动态加载,即修改动态组件的 is 标签,触发异步组件的加载。

3. webpack - require.context

【 demo 地址 】

使用 webpack 打包,模块需要通过 es6-import 或是 require 的方式导入。当导入的组件较多时,一个个导入,会比较繁琐。【方式2】使用 vue 的动态&异步组件实现了懒加载,但需要显式地指定所有需要加载的组件,幸运的是,webpack 提供了 require.context 的 api 供开发者动态导入模块,这样开发者甚至可以根据接口返回动态地加载组件,下面是一个 demo:

代码语言:txt
复制
<template>
  <div id="app">
    <component :is="app"></component>
  </div>
</template>
<script>
import Vue from 'vue'
export default {
  data () {
    return {
      app: ''
    }
  },
  created () {
    // 模拟异步请求
    setTimeout(() => {
      const requireComponent = require.context('./comps', false, /comp[0-9]+\.(vue|js)$/)
      requireComponent.keys().forEach(fileName => {
        const componentConfig = requireComponent(fileName)
        const componentName = fileName.split('/').pop().replace(/\.\w+$/, '')
        Vue.component(
          componentName,
          componentConfig.default || componentConfig
        )
      })
      // 修改动态组件 is 标签
      setTimeout(() => {
        this.app = 'comp2'
      }, 2000)
    }, 1000)
  }
}
</script>

require.context 需要传入三个参数,参数1为组件目录的相对路径,参数2为是否查询其子目录,参数3为匹配组件文件名的正则表达式:

代码语言:txt
复制
const requireComponent = require.context(
	'./comps', // 其组件目录的相对路径
	false, // 是否查询其子目录
	/comp[0-9]+\.(vue|js)$/ // 匹配组件文件名的正则表达式
)

遍历 require.context 返回值的 key,并注册,若这个组件选项是通过 export default 导出的会优先使用 .default

代码语言:txt
复制
requireComponent.keys().forEach(fileName => {
	const componentConfig = requireComponent(fileName) // 获取组件配置
	const componentName = fileName.split('/').pop().replace(/\.\w+$/, '')
	// 全局注册组件
	Vue.component(
		componentName,
		componentConfig.default || componentConfig
	)
})

4. vue 子组件独立打包

【 demo 地址 】

上面的【方式3】解决了【方式2】显式指定全部组件的不便,但动态组件仍需要和主项目一起打包,在一些场景下则显得不便,最理想的状态应该是:主程序和子组件独立打包,能够根据异步接口的返回结果动态地加载组件。

4.1 webpack + vue-loader

webpack 中 vue 子组件独立打包,需要使用对应的 vue-loader 识别 vue 文件,见 01-webpack,可以参考 vue-loader 文档,vue-loader文档地址,需要配置 webpack.config.js

代码语言:txt
复制
{
	test: /\.vue$/,
	loader: 'vue-loader'
}

构建的组件的使用

代码语言:txt
复制
<!-- 动态组件 -->
<div :is="compName"></div>

动态载入 build 后的 bundle

代码语言:txt
复制
loadScript('xxx').then(() => {
  Vue.component(compName, window[compName].default);
  this.compName = compName;
})

4.2 vue-cli

vue 官方提供的脚手架 vue-cli 集成了 vue-loader,开箱即用,可以轻松实现独立入口打包。见 02-vue-lib,参考 vue-cli 文档,vue-cli 文档地址

代码语言:txt
复制
# 将一个单独的入口构建为一个库
$ vue-cli-service build --target lib --name myLib [entry]

4.3 导入动态组件脚本文件

经过打包的组件可以生成 js 脚本文件或 lib 库文件,可以根据接口等方式的返回结果,通过 scriptimport 的方式引入,见 03-vue-lib

代码语言:txt
复制
loadScript('http://xxx/xx.js').then(() => {
	Vue.component(compName, window[compName].default || window[compName]);
	this.compName = compName;
})

5. 使用场景总结

本文总结了三种组件动态加载的方式,其中:

(1) vue 动态 & 异步组件的方式最简单,能够实现组件的懒加载,可以在普通项目中直接使用,但需要显式地指定所有动态组件并和主程序一起打包,适合大部分场景;

(2) webpack 的 require.context 方式支持用正则表达式的方式异步导入组件,适合导入多个文件名满足一定规律的组件,并且支持从接口等方式,根据返回结果异步加载组件,但是仍然需要和主程序一起打包,适合多人同时在一个项目下开发,并且子组件迭代频繁,需要通过文件名的正则表达式动态载入的场景;

(3) 子组件独立打包的方式通过 vue-loader 等 webpack 插件,对子组件独立打包,并根据接口返回结果动态加载,但是实现较为复杂,适合大型系统用于扩展插件,或者在不开放源码的前提下实现项目间的组件调用。

独立打包不仅能够缩短项目的打包时间,减少打包文件体积,加快加载速度,还能实现项目间的组件调用。在实践中,我们需要根据不同场景选择适合的方式。

6. 参考资料

  1. 动态组件 & 异步组件 (https://cn.vuejs.org/v2/guide/components-dynamic-async.html)
  2. Webpack-require.context (https://webpack.js.org/guides/dependency-management/#requirecontext)
  3. Vue-loader手动设置 (https://vue-loader.vuejs.org/zh/guide/#手动设置)
  4. Vue-cli 应用 (https://cli.vuejs.org/zh/guide/build-targets.html#应用)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 背景
  • 2. vue 动态 & 异步组件
    • 2.1 动态组件实现组件动态切换
      • 2.2 异步组件实现懒加载
        • 2.3 动态 & 异步组件实现组件动态加载
        • 3. webpack - require.context
        • 4. vue 子组件独立打包
          • 4.1 webpack + vue-loader
            • 4.2 vue-cli
              • 4.3 导入动态组件脚本文件
              • 5. 使用场景总结
              • 6. 参考资料
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档