加载 vue 远程代码的组件实例详解(2)
至此我们的模块已经被编译成框架可以识别的文件。
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); }
内容版权声明:除非注明,否则皆为本站原创文章。