加载 vue 远程代码的组件实例详解

在我们的 vue 项目中(特别是后台系统),总会出现一些需要多业务线共同开发同一个项目的场景,如果各业务团队向框架中提供一些私有的展示组件,但是这些组件并不能和框架一起打包,因为框架不能因为某个私有模块的频繁变更而重复构建发布。在这种场景下我们需要一个加载远程异步代码的组件来完成将这些组件加载到框架中。

vue-cli 作为 Vue 官方推荐的项目构建脚手架,它提供了开发过程中常用的,热重载,构建,调试,单元测试,代码检测等功能。我们本次的异步远端组件将基于 vue-cli 开发。

需求分析

  1. 如何加载远端的代码?
  2. 如何注册加载后的代码到框架中。
  3. 父组件如何和远端引入的组件通信。
  4. 远端代码如何复用框架中已引入的库。
  5. 避免因远端代码被类似 v-for 多次调用导致的不必要请求。

加载远端代码

远端代码应该存储在一个可访问的 URL 上,这样我们通过 Axios 类似的 HTTP client 请求这个链接拿到源码。

import Axios from 'axios';
export default {
 name: 'SyncComponent',
 props: {
  // 父组件提供请求地址
  url: {
   type: String,
   default: ''
  }
 },
 data() {
  return {
   resData: ''
  };
 },
 async mounted() {
  if (!this.url) return;
  const res = await Axios.get(this.url); // 我们在组件挂载完成时,请求远端代码并存储结果。
  this.resData = res.data;
 }
};

以上是基础代码 为了方便 一下例子中 我将省略重复的代码部分。

注册代码到框架中

这部分有些繁琐,涉及到多个问题:

浏览器并不支持 .vue 模板 或 ES.next 语法,模块需要编译后才可以使用。

处理这部分比较简单,我们自己定义一个webpack配置文件来打包这些模板。

// 在 build 目录下新建 webpack.sync-components.prod.conf.js 文件
const webpack = require('webpack');
const path = require('path');
const utils = require('./utils');
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
function resolve(dir) {
 return path.join(__dirname, '..', dir)
}
module.exports = {
 // 此处引入要打包的组件
 entry: {
  componentA: resolve('/src/views/component-a.vue')
 },
 // 输出到静态目录下
 output: {
  path: resolve('/static/'),
  filename: '[name].js',
 },
 resolve: {
  extensions: ['.js', '.vue', '.json'],
  alias: {
   'vue$': 'vue/dist/vue.esm.js',
   '@': resolve('src'),
  }
 },
 module: {
  rules: [
   {
    test: /\.vue$/,
    loader: 'vue-loader',
    options: {
     esModule: false, // ****** vue-loader v13 更新 默认值为 true v12及之前版本为 false, 此项配置影响 vue 自身异步组件写法以及 webpack 打包结果
     loaders: utils.cssLoaders({
      sourceMap: true,
      extract: false     // css 不做提取
     }),
     transformToRequire: {
      video: 'src',
      source: 'src',
      img: 'src',
      image: 'xlink:href'
     }
    }
   },
   {
    test: /\.js$/,
    loader: 'babel-loader',
    include: [resolve('src'), resolve('test')]
   },
   {
    test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
    loader: 'url-loader',
    options: {
     limit: 10000,
     name: utils.assetsPath('img/[name].[hash:7].[ext]')
    }
   },
   {
    test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
    loader: 'url-loader',
    options: {
     limit: 10000,
     name: utils.assetsPath('media/[name].[hash:7].[ext]')
    }
   },
   {
    test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
    loader: 'url-loader',
    options: {
     limit: 10000,
     name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
    }
   }
  ]
 },
 plugins: [
  new webpack.DefinePlugin({
   'process.env.NODE_ENV': '"production"'
  }),
  // 压缩JS
  new webpack.optimize.UglifyJsPlugin({
   compress: false,
   sourceMap: true
  }),
  // 压缩CSS 注意不做提取
  new OptimizeCSSPlugin({
   cssProcessorOptions: {
    safe: true
   }
  })
 ]
};

至此我们的模块已经被编译成框架可以识别的文件。

1.如何将字符串转换成js对象。

new Function。
async mounted() {
 if (!this.url) return;
 const res = await Axios.get(this.url);
 let Fn = Function;
 this.mode = new Fn(`return ${res.data}`)();
}

1.转换后的js对象并不能被vue识别。

有两种可能会导致这个问题:

// vue-loader v13 esModule 更新 默认值为 true, v12及之前版本为 false, 此项配置影响 vue 自身异步组件写法以及 webpack 打包结果
{
 test: /\.vue$/,
 loader: 'vue-loader',
 options: {
  esModule: false
  ... 以下省略千军万码
 }
}
// UglifyJs 需要取消变量名替换配置,此配置并不会极大影响压缩率
new webpack.optimize.UglifyJsPlugin({
 compress: false,
 sourceMap: true
})

至此 远程组件就被引入到框架中了。

父组件如何和远端引入的组件通信

这里有一个问题,从 view组件 到 远程异步加载组件 再到 实际业务组件 通信一共三层,中间层 远程异步组件 作为公共组件不可被修改,需要 view组件 直接向 实际业务组件 通信。vuex 和 eventBus 方案都过于繁琐,这里我们采用 $attrs 和 $listeners(vue v2.4+), 来实现 “fallthrough”(vue组件跨层级通信)。

// 修改 sync-component.vue 组件
// 新增 v-bind="$attrs" v-on="$listeners"
<component
 :is="mode"
 v-bind="$attrs"
 v-on="$listeners">
</component>
// inheritAttrs: true
export default {
 name: 'SyncComponent',
 props: {
  // 父组件提供请求地址
  url: {
   type: String,
   default: ''
  }
 },
 inheritAttrs: true
 ... 以下省略千军万码
}

远端代码如何复用框架中已引入的库

我们不希望看到远端组件和框架中存在较大库或插件的重复的引入,这部分内容尚处在实践阶段,主要思路是把公共库挂载到Vue原型链上实现组件公共复用 Vue.prototype.$xxx。

// 全局添加 axios 对象
import axios from 'axios';
Vue.prototype.$http = axios;

引入的远程组件可以访问到框架中的公共包了,这时候还需要配置 webpack 使远程组件打包时不要包含公共包的代码。

// webpack.sync-components.prod.conf.js 添加
externals: {
 vue: 'vue',
 'element-ui': 'element-ui',
 axios: 'axios'
}

避免因远端代码被类似 v-for 多次调用导致的不必要请求。

这部分我们直接用一个全局变量做字典,存储 以 请求地址:数据 为子项的数组。

async mounted() {
 if (!this.url) return;
 // Cache 缓存 根据 url 参数
 if (!window.SyncComponentCache) {
  window.SyncComponentCache = {};
 }
 let res;
 if (!window.SyncComponentCache[this.url]) {
  window.SyncComponentCache[this.url] = Axios.get(this.url);
  res = await window.SyncComponentCache[this.url];
 } else {
  res = await window.SyncComponentCache[this.url];
 }
 let Fn = Function;
 this.mode = new Fn(`return ${res.data}`)();
 console.log(this.mode);
}

至此,异步远程组件就可以加载并和框架进行通信了。

本文中的源码请访问 github 获取,组件已经发布到NPM上,可以直接安装。

总结

以上所述是小编给大家介绍的加载 vue 远程代码的组件,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Vue-router 类似Vuex实现组件化开发的示例

    本文介绍了Vue-router 类似Vuex实现组件化开发的示例,分享给大家,具体如下: 随着项目越来越大,把所有route写在一个文件里就显得杂乱. #单个组件路由 import a from '../components/a' export default { path: '/a', name: 'a', component: a } import arouter from 'xxx' export default new Router({ routes: [ arouter ] }) #多

  • vue父组件中获取子组件中的数据(实例讲解)

    如下所示: <FormItem label="上传头像" prop="image"> <uploadImg :width="150" :height="150" :name="'avatar'" size="150px*150px" ref="avatar"></uploadImg> </FormItem> <Fo

  • Vue2.0父组件与子组件之间的事件发射与接收实例代码

    关于vue2.0的事件发射和接收,大家都知道$dispatch和$broadcast在vue2.0已经被弃用了,取而代之的是更加方便快捷的方式,使用事件中心,组件通过它来互相通信,不管组件在哪一个层都可以通过实例化一个空Vue来实现.上案例: 这是自己写的一个小案例,功能就是点击子组件的加减按钮控制父组件的数量变化.原理就是子组件的加减按钮点击时分发事件,父组件接收事件.相信html和css的代码大家都没问题,这里不赘述,直接说js部分,首先在项目初始化时先给data添加名为eventHub的空

  • vue 计时器组件的实现代码

    整理文档,搜刮出一个vue 计时器组件的代码,稍微整理精简一下做下分享. <template> <div> <span :sendSync="sendSync" :autoStart="autoStart" :defaultVal="defaultVal" >{{countString}}</span> </div> </template> <script> ex

  • vue webuploader 文件上传组件开发

    最近项目中需要用到百度的webuploader大文件的分片上传,对接后端的fastdfs,于是着手写了这个文件上传的小插件,步骤很简单,但是其中猜到的坑也不少,详细如下: 一.封装组件 引入百度提供的webuploader.js.Uploader.swf css样式就直接写在组件里面了 <template> <div> <div id="list" class="uploader-list"></div> <di

  • 加载 vue 远程代码的组件实例详解

    在我们的 vue 项目中(特别是后台系统),总会出现一些需要多业务线共同开发同一个项目的场景,如果各业务团队向框架中提供一些私有的展示组件,但是这些组件并不能和框架一起打包,因为框架不能因为某个私有模块的频繁变更而重复构建发布.在这种场景下我们需要一个加载远程异步代码的组件来完成将这些组件加载到框架中. vue-cli 作为 Vue 官方推荐的项目构建脚手架,它提供了开发过程中常用的,热重载,构建,调试,单元测试,代码检测等功能.我们本次的异步远端组件将基于 vue-cli 开发. 需求分析 如

  • vue的toast弹窗组件实例详解

    相信普通的vue组件大家都会写, 定义 -> 引入 -> 注册 -> 使用 ,行云流水,一气呵成,但是如果我们今天是要自定义一个弹窗组件呢? 首先,我们来分析一下弹窗组件的特性(需求): 0. 轻量 --一个组件小于 1Kib (实际打包完不到0.8k) 1.一般都是多处使用 --需要解决每个页面重复引用+注册 1.一般都是跟js交互的 --无需 在 <template> 里面写 <toast :show="true" text="弹窗消息

  • IOS中Weex 加载 .xcassets 中的图片资源的实例详解

    IOS中Weex 加载 .xcassets 中的图片资源的实例详解 前言: 因为 .xcassets 中的图片资源只能通过 imageNamed: 方法加载,所以需要做一些特殊处理,才能提供给 Weex 使用(PS:纯属娱乐,因为 Weex 跨平台的特性,这种针对某一端做实现的方案实用价值并不大). 方案 观察 WeexSDK 发现有 WXImgLoaderProtocol 这个协议,这个协议包含了下面的方法: - (id<WXImageOperationProtocol>)downloadI

  • vue实现简单表格组件实例详解

    本来想这一周做一个关于vuex的总结的,但是由于朋友反应说还不知道如何用vue去写一个组件,所以在此写写一篇文章来说明下如何去写vue页面或者组件.vue的核心思想就是组件,什么是组件呢?按照我的理解组件就是装配页面的零件,比如一辆车有大大小小许多零件组成,那么同样的一个页面,也是有许多组件构成的比如说头部组件 按钮组件等等,vue三大核心组件 路由 状态管理,路由控制页面的渲染,页面由组件组成,数据有vuex进行管理和改变.下面我会以一个简单的案例来说 第一步:构建一个简单的vue项目,老规矩

  • 基于vue+canvas的excel-like组件实例详解

    a vue component,基于vue的表格组件,主要解决大数据量的表格渲染性能问题,使用canvas绘制表格,同时支持类似excel的批量选中,复制黏贴删除,实时编辑等功能. vue-grid-canvas Install NPM / Yarn Install the package: npm install vue-canvas-grid --save Then import it in your project import Vue from 'vue' import Grid fro

  • 微信小程序 图片加载(本地,网路)实例详解

    在微信小程序中,要显示一张图片,有两种图片加载方式: 加载本地图片 加载网络图片 加载本地图片 <image class="widget__arrow" src="/image/arrowright.png" mode="aspectFill"> </image> src="/image/arrowright.png" 这句就是加载本地图片资源的.想想iOS中的加载本地图片,imageName:,类似.

  • JVM加载class文件的原理机制实例详解

    目录 一.JVM简介 二.JVM的组成部分 三.JVM加载class文件的原理机制 一.JVM简介 JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的. Java语言的一个非常重要的特点就是与平台的 无关性.而使用Java虚拟机是实现这一特点的关键.一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码.而引入Java语言虚拟机后,Java语言在不同

  • vue组件编写之todolist组件实例详解

    我们在topNav这个页面上插入一个todolist子组件 我不知道怎么回事,这里的markdown的代码总是串行..所以代码看得不舒服,见谅啊,我最后会放github的源代码地址. 1. 父组件topNav中注册子组件,引入子组件 <template> <div> <p>下面这一行就是定义的组件名称</p> <todo-list></todo-list> <router-view></router-view>

  • Vue的事件响应式进度条组件实例详解

    写在前面 找了很多vue进度条组件,都不包含拖拽和点击事件,input range倒是原生包含input和change事件,但是直接基于input range做进度条的话,样式部分需要做大量调整和兼容性处理.即使做好了,将来需要修改外观,又是一番折腾. 基于以上两个原因,做了一个可以响应input和change事件(即一个是拖动进度条到某处,一个是在进度条某位置点击使其值变为该位置)的div实现的Vue组件,这样既满足了对进度条事件的需求,也带来了如有需求变动,样式修改很方便的好处. 效果图 以

  • Vue首评加载速度及白屏时间优化详解

    目录 项目背景 splitChunks CDN GZIP 删除文件预加载 项目背景 测试环境的管理后台应客户需求最近加了点东西,加载的东西变多,使得整个项目变得有点臃肿了,首屏以及刷新后渲染速度变得极其缓慢.之前10s左右还能勉强接受,这次一下干到30s,整个人都崩溃了,花了点时间优化了一下. 环境:vue:2.6.11,vue-cli:3.0 splitChunks 看到上面图片里的文件其实并不大,最大的也就287k. 这也是优化过的,之前都是有的最大为1m左右,在vue.config.js配

随机推荐