摘要:目前采用動態加載異步組件的方式來實現小組件之間的通信。內容使用過的都應該知道的動態加載組件通過來綁定需要加載的組件。總結本篇主要借助的動態組件和打包單文件來實現動態加載異步組件,通過的事件總線掛載在上來實現平級組件之間的通信。
背景:
目前我們項目都是按組件劃分的,然后各個組件之間封裝成產品。目前都是采用iframe直接嵌套頁面。項目中我們還是會碰到一些通用的組件跟業務之間有通信,這種情況下iframe并不是最好的選擇,iframe存在跨域的問題,當然是postMessage還是可以通信的,但也并非是最好的。目前有這么一個場景:門戶需要制作通用的首頁和數據概覽頁面,首頁和數據概覽頁面通過小部件來自由拼接。業務組件在制作的時候只需要提供各個模塊小部件的url就可以了,可是如果小部件之間還存在聯系呢?那么iframe是不好的。目前采用Vue動態加載異步組件的方式來實現小組件之間的通信。當然門戶也要提供一個通信的基線:Vue事件總線(空的Vue實例對象)。
內容:使用過vue的都應該知道vue的動態加載組件components:
Vue通過is來綁定需要加載的組件。那么我們現在需要的就是如何打包組件,如果通過復制業務組件內部的代碼,那么這種就需要把依賴全部找齊,并復制過去(很多情況下會漏下某個圖片或css等),這種方式是比較low的,不方便維護。因此我們需要通過webpack來打包單個vue文件成js,這邊一個vue打包成一個js,不需壓代碼分割,css分離。因為component加載時只需要加載一個文件即可。打包文件配置如下:
首先在package.json加入打包命令:
"scripts": { ... "build-outCMP": "node build/build-out-components.js" },
Build-out-components.js文件:
"use strict" require("./check-versions")() process.env.NODE_ENV = "production" const ora = require("ora") const path = require("path") const chalk = require("chalk") const webpack = require("webpack") const webpackConfig = require("./webpack.out-components.prod.conf") const spinner = ora("building for sync-components...") spinner.start() webpack(webpackConfig, function (err, stats) { spinner.stop() if (err) throw err process.stdout.write(stats.toString({ colors: true, modules: false, children: false, chunks: false, chunkModules: false }) + " ") if (stats.hasErrors()) { console.log(chalk.red(" Build failed with errors. ")) process.exit(1) } console.log(chalk.cyan(" Build complete. ")) console.log(chalk.yellow( " Tip: built files are meant to be served over an HTTP server. " + " Opening index.html over file:// won"t work. " )) })
webpack.out-components.prod.conf.js文件配置如下
const webpack = require("webpack"); const path = require("path"); const utils = require("./utils"); const OptimizeCSSPlugin = require("optimize-css-assets-webpack-plugin") const {entry, mkdirsSync} = require("./out-components-tools") function resolve(dir) { return path.join(__dirname, "..", dir) } mkdirsSync(resolve("/static/outComponents")) module.exports = { entry: entry, output: { path: resolve("/static/outComponents"), filename: "[name].js", }, resolve: { extensions: [".js", ".vue", ".json"], alias: { "vue$": "vue/dist/vue.esm.js", "@": resolve("src"), } }, externals: { vue: "vue", axios: "axios" }, 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"" }), // UglifyJs do not support ES6+, you can also use babel-minify for better treeshaking: https://github.com/babel/minify new webpack.optimize.UglifyJsPlugin({ compress: false, sourceMap: true }), // Compress extracted CSS. We are using this plugin so that possible // duplicated CSS from different components can be deduped. new OptimizeCSSPlugin({ cssProcessorOptions: { safe: true } }) ] };
out-components-tools.js文件配置如下:
const glob = require("glob") const fs = require("fs"); const path = require("path"); // 遍歷要打包的組件 let entry = {} var moduleSrcArray = glob.sync("./src/out-components/*") for(var x in moduleSrcArray){ let fileName = (moduleSrcArray[x].split("/")[3]).slice(0, -4) entry[fileName] = moduleSrcArray[x] } // 清理文件 function mkdirsSync(dirname) { if (fs.existsSync(dirname)) { deleteall(dirname) return true; } else { if (mkdirsSync(path.dirname(dirname))) { fs.mkdirSync(dirname); return true; } } } // 刪除文件下的文件 function deleteall(path) { ??var files = []; ??if(fs.existsSync(path)) { ????files = fs.readdirSync(path); ????files.forEach(function(file, index) { ??????var curPath = path + "/" + file; ??????if(fs.statSync(curPath).isDirectory()) { // recurse ????????deleteall(curPath); ??????} else { // delete file ????????fs.unlinkSync(curPath); ??????} ????}); ??} }; exports.entry = entry exports.mkdirsSync = mkdirsSync
build-out-components是打包的入口文件,webpack.out-components.prod.conf.js是webpack打包的配置文件,out-components-tools.js是工具庫,這邊是打包的entry自動獲取(默認為src/out-components),還有自動刪除之前打包的文件。
目前的文件目錄為
通過打包生產文件:
在static下outComponents文件夾內的js文件。(最終打包需要打包到dist下面,這邊做測試先打包在static文件下,方便后續動態組件ajax獲取組件使用)
門戶的小部件是通過配置url,和調整布局來生產的。因此業務組件至此已經完成了。只需要提供對門戶暴露的url即可。 接下來就是門戶這邊加載動態組件的實現了。門戶這邊就相對簡單了。看如下圖配置:
門戶通過component的動態組件來實現加載異步組件,通過ajax請求剛才打包的url,然后實例化函數new Function來賦值給mode(new Function之所以分成2部,是因此效驗規則的問題,可忽略)。如下圖演示
這樣就實現了動態加載異步組件了。門戶和業務組件可以各個開發,任何業務開發數據概覽,門戶都不需要改代碼,只需要界面上配置url即可。這個異步加載組件已經結束了。這邊門戶需要封裝一封實現異步組件。父級只需要傳入url即可。這邊還有個可以優化的是,可以把mode優先緩存,那么不需要每次都去加載請求。如下:
我們可以看到在門戶的一個數據概覽頁面上加載了多個異步組件,那么異步組件之間也是可能存在通信的,這樣該如何做呢?因為現在已經不是iframe嵌套了,可以通過監聽一個組件,然調用另一個組件的方法,這樣確實可以實現平級組件間的通信,但這樣勢必不可取的,因為一旦這樣做了門戶必須要根據業務來輔助,修改代碼來實現功能。因此這邊借用門戶來生成vue事件總線(空的vue實例)來實現。
門戶代碼如下: 在this.$root上掛在一個事件總線:
created () { if (!this.$root.eventBus) { this.$root.eventBus = new Vue() } }
然后業務組件之間就可以根據自己的業務實現通信:
組件一和組件二代碼如下:
這是一個外部組件a1
這也是外部組件哦這是a1傳來的{{a1}}
業務組件就可以根據this.$root.eventBus和vue上的事件傳遞($emit, $on)來實現相互的通信。
總結:本篇主要借助vue的動態組件和webpack打包單文件來實現動態加載異步組件,通過vue的事件總線掛載在this.$root上來實現平級組件之間的通信。
拓展方向:這個方式不僅僅可以應用在門戶單個頁面上的小部件上,同樣如果某個項目中的頁面文件需要復用時,不想通過代碼的復制,同樣可以再那個文件配置打包單文件配置,打包出的文件在領一個項目中動態加載出來即可。這種模式與通用組件的install模式是有點類似的,只是這個單文件vue不是通用的,但同樣可以達到打包復用頁面。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108691.html
摘要:動態組件如果我們打算在一個地方根據不同的狀態引用不同的組件的話,比如頁,那么給我們提供動態組件。實現動態組件的加載。的值可以是一個已經注冊的組件的名字或者一個組件的選對象。 動態組件 如果我們打算在一個地方根據不同的狀態引用不同的組件的話,比如tab頁,那么Vue給我們提供動態組件。 基本使用 Parent.vue {{btn.name}} ...
摘要:發現了動態組件異步組件這個東西簡直是救命啊動態組件異步組件思路分析有了動態組件這個東西之后,我們就可以根據綁定不同的值來渲染不同的組件。每個組件要傳給子組件的值和接收子組件的事件也可以動態的綁定上去。 推動我實現這個功能的業務背景 最近接到一個讓我很頭疼的需求:產品要求我們系統頁面上所有的模塊都支持順序的變動。比如有 模塊A、B、C、D,可以無序的展示在頁面上,我剛聽到這個需求的時候我...
摘要:,常規組件,卒。小結總之呢,上面分析了在中編譯遠程模板的可能性,最后得出了兩種方法異步組件,應該是官方的推薦方法動態組件,變通之法,論壇上發現的思路當然如果有其他方法歡迎交流,本文如果有不嚴謹不正確的地方也歡迎指出本文發自我的,原文鏈接我的 說明 有些時候你可能需要從后臺獲取模板,并在前臺在自己編譯,這在用 AngularJS 1.x 的時候似乎很常見,可以直接用 ng-include...
摘要:,常規組件,卒。小結總之呢,上面分析了在中編譯遠程模板的可能性,最后得出了兩種方法異步組件,應該是官方的推薦方法動態組件,變通之法,論壇上發現的思路當然如果有其他方法歡迎交流,本文如果有不嚴謹不正確的地方也歡迎指出本文發自我的,原文鏈接我的 說明 有些時候你可能需要從后臺獲取模板,并在前臺在自己編譯,這在用 AngularJS 1.x 的時候似乎很常見,可以直接用 ng-include...
摘要:當一個的項目體積變得十分龐大的時候,使用的代碼分離功能將,或的代碼進行分離并按需加載,會極大的提高的首屏加載速度。如果我們使用函數在中返回模塊作為載荷,就實現了懶加載。 當一個Vue的項目體積變得十分龐大的時候,使用Webpack的代碼分離功能將Vue Components,routes或Vuex的代碼進行分離并按需加載,會極大的提高App的首屏加載速度。 showImg(https:...
閱讀 2283·2021-09-30 09:47
閱讀 2210·2021-09-26 09:55
閱讀 2938·2021-09-24 10:27
閱讀 1534·2019-08-27 10:54
閱讀 960·2019-08-26 13:40
閱讀 2486·2019-08-26 13:24
閱讀 2411·2019-08-26 13:22
閱讀 1720·2019-08-23 18:38