成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Vue動(dòng)態(tài)加載異步組件

awesome23 / 2428人閱讀

摘要:目前采用動(dòng)態(tài)加載異步組件的方式來實(shí)現(xiàn)小組件之間的通信。內(nèi)容使用過的都應(yīng)該知道的動(dòng)態(tài)加載組件通過來綁定需要加載的組件??偨Y(jié)本篇主要借助的動(dòng)態(tài)組件和打包單文件來實(shí)現(xiàn)動(dòng)態(tài)加載異步組件,通過的事件總線掛載在上來實(shí)現(xiàn)平級(jí)組件之間的通信。

背景:

目前我們項(xiàng)目都是按組件劃分的,然后各個(gè)組件之間封裝成產(chǎn)品。目前都是采用iframe直接嵌套頁面。項(xiàng)目中我們還是會(huì)碰到一些通用的組件跟業(yè)務(wù)之間有通信,這種情況下iframe并不是最好的選擇,iframe存在跨域的問題,當(dāng)然是postMessage還是可以通信的,但也并非是最好的。目前有這么一個(gè)場景:門戶需要制作通用的首頁和數(shù)據(jù)概覽頁面,首頁和數(shù)據(jù)概覽頁面通過小部件來自由拼接。業(yè)務(wù)組件在制作的時(shí)候只需要提供各個(gè)模塊小部件的url就可以了,可是如果小部件之間還存在聯(lián)系呢?那么iframe是不好的。目前采用Vue動(dòng)態(tài)加載異步組件的方式來實(shí)現(xiàn)小組件之間的通信。當(dāng)然門戶也要提供一個(gè)通信的基線:Vue事件總線(空的Vue實(shí)例對(duì)象)。

內(nèi)容:

使用過vue的都應(yīng)該知道vue的動(dòng)態(tài)加載組件components:

Vue通過is來綁定需要加載的組件。那么我們現(xiàn)在需要的就是如何打包組件,如果通過復(fù)制業(yè)務(wù)組件內(nèi)部的代碼,那么這種就需要把依賴全部找齊,并復(fù)制過去(很多情況下會(huì)漏下某個(gè)圖片或css等),這種方式是比較low的,不方便維護(hù)。因此我們需要通過webpack來打包單個(gè)vue文件成js,這邊一個(gè)vue打包成一個(gè)js,不需壓代碼分割,css分離。因?yàn)閏omponent加載時(shí)只需要加載一個(gè)文件即可。打包文件配置如下:
首先在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 更新 默認(rèn)值為 true v12及之前版本為 false, 此項(xiàng)配置影響 vue 自身異步組件寫法以及 webpack 打包結(jié)果
          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自動(dòng)獲取(默認(rèn)為src/out-components),還有自動(dòng)刪除之前打包的文件。
目前的文件目錄為

通過打包生產(chǎn)文件:

在static下outComponents文件夾內(nèi)的js文件。(最終打包需要打包到dist下面,這邊做測試先打包在static文件下,方便后續(xù)動(dòng)態(tài)組件ajax獲取組件使用)

門戶的小部件是通過配置url,和調(diào)整布局來生產(chǎn)的。因此業(yè)務(wù)組件至此已經(jīng)完成了。只需要提供對(duì)門戶暴露的url即可。
接下來就是門戶這邊加載動(dòng)態(tài)組件的實(shí)現(xiàn)了。門戶這邊就相對(duì)簡單了??慈缦聢D配置:

門戶通過component的動(dòng)態(tài)組件來實(shí)現(xiàn)加載異步組件,通過ajax請(qǐng)求剛才打包的url,然后實(shí)例化函數(shù)new Function來賦值給mode(new Function之所以分成2部,是因此效驗(yàn)規(guī)則的問題,可忽略)。如下圖演示

這樣就實(shí)現(xiàn)了動(dòng)態(tài)加載異步組件了。門戶和業(yè)務(wù)組件可以各個(gè)開發(fā),任何業(yè)務(wù)開發(fā)數(shù)據(jù)概覽,門戶都不需要改代碼,只需要界面上配置url即可。這個(gè)異步加載組件已經(jīng)結(jié)束了。這邊門戶需要封裝一封實(shí)現(xiàn)異步組件。父級(jí)只需要傳入url即可。這邊還有個(gè)可以優(yōu)化的是,可以把mode優(yōu)先緩存,那么不需要每次都去加載請(qǐng)求。如下:

我們可以看到在門戶的一個(gè)數(shù)據(jù)概覽頁面上加載了多個(gè)異步組件,那么異步組件之間也是可能存在通信的,這樣該如何做呢?因?yàn)楝F(xiàn)在已經(jīng)不是iframe嵌套了,可以通過監(jiān)聽一個(gè)組件,然調(diào)用另一個(gè)組件的方法,這樣確實(shí)可以實(shí)現(xiàn)平級(jí)組件間的通信,但這樣勢必不可取的,因?yàn)橐坏┻@樣做了門戶必須要根據(jù)業(yè)務(wù)來輔助,修改代碼來實(shí)現(xiàn)功能。因此這邊借用門戶來生成vue事件總線(空的vue實(shí)例)來實(shí)現(xiàn)。

門戶代碼如下: 在this.$root上掛在一個(gè)事件總線:

    created () {
        if (!this.$root.eventBus) {
          this.$root.eventBus = new Vue()
        }
      }

然后業(yè)務(wù)組件之間就可以根據(jù)自己的業(yè)務(wù)實(shí)現(xiàn)通信:
組件一和組件二代碼如下:

    
    
    
    
    
    

業(yè)務(wù)組件就可以根據(jù)this.$root.eventBus和vue上的事件傳遞($emit, $on)來實(shí)現(xiàn)相互的通信。

總結(jié):本篇主要借助vue的動(dòng)態(tài)組件和webpack打包單文件來實(shí)現(xiàn)動(dòng)態(tài)加載異步組件,通過vue的事件總線掛載在this.$root上來實(shí)現(xiàn)平級(jí)組件之間的通信。

拓展方向:這個(gè)方式不僅僅可以應(yīng)用在門戶單個(gè)頁面上的小部件上,同樣如果某個(gè)項(xiàng)目中的頁面文件需要復(fù)用時(shí),不想通過代碼的復(fù)制,同樣可以再那個(gè)文件配置打包單文件配置,打包出的文件在領(lǐng)一個(gè)項(xiàng)目中動(dòng)態(tài)加載出來即可。這種模式與通用組件的install模式是有點(diǎn)類似的,只是這個(gè)單文件vue不是通用的,但同樣可以達(dá)到打包復(fù)用頁面。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/108691.html

相關(guān)文章

  • Vue動(dòng)態(tài)組件異步組件

    摘要:動(dòng)態(tài)組件如果我們打算在一個(gè)地方根據(jù)不同的狀態(tài)引用不同的組件的話,比如頁,那么給我們提供動(dòng)態(tài)組件。實(shí)現(xiàn)動(dòng)態(tài)組件的加載。的值可以是一個(gè)已經(jīng)注冊的組件的名字或者一個(gè)組件的選對(duì)象。 動(dòng)態(tài)組件 如果我們打算在一個(gè)地方根據(jù)不同的狀態(tài)引用不同的組件的話,比如tab頁,那么Vue給我們提供動(dòng)態(tài)組件。 基本使用 Parent.vue {{btn.name}} ...

    nanchen2251 評(píng)論0 收藏0
  • 利用VUE異步組件、動(dòng)態(tài)加載組件,實(shí)現(xiàn)自定義組件順序、動(dòng)態(tài)綁定傳入子組件的props、動(dòng)態(tài)綁定監(jiān)聽子

    摘要:發(fā)現(xiàn)了動(dòng)態(tài)組件異步組件這個(gè)東西簡直是救命啊動(dòng)態(tài)組件異步組件思路分析有了動(dòng)態(tài)組件這個(gè)東西之后,我們就可以根據(jù)綁定不同的值來渲染不同的組件。每個(gè)組件要傳給子組件的值和接收子組件的事件也可以動(dòng)態(tài)的綁定上去。 推動(dòng)我實(shí)現(xiàn)這個(gè)功能的業(yè)務(wù)背景 最近接到一個(gè)讓我很頭疼的需求:產(chǎn)品要求我們系統(tǒng)頁面上所有的模塊都支持順序的變動(dòng)。比如有 模塊A、B、C、D,可以無序的展示在頁面上,我剛聽到這個(gè)需求的時(shí)候我...

    marser 評(píng)論0 收藏0
  • VueJS 如何編譯服務(wù)器端遠(yuǎn)程模板【異步組件+簡單方法】

    摘要:,常規(guī)組件,卒。小結(jié)總之呢,上面分析了在中編譯遠(yuǎn)程模板的可能性,最后得出了兩種方法異步組件,應(yīng)該是官方的推薦方法動(dòng)態(tài)組件,變通之法,論壇上發(fā)現(xiàn)的思路當(dāng)然如果有其他方法歡迎交流,本文如果有不嚴(yán)謹(jǐn)不正確的地方也歡迎指出本文發(fā)自我的,原文鏈接我的 說明 有些時(shí)候你可能需要從后臺(tái)獲取模板,并在前臺(tái)在自己編譯,這在用 AngularJS 1.x 的時(shí)候似乎很常見,可以直接用 ng-include...

    褰辯話 評(píng)論0 收藏0
  • VueJS 如何編譯服務(wù)器端遠(yuǎn)程模板【異步組件+簡單方法】

    摘要:,常規(guī)組件,卒。小結(jié)總之呢,上面分析了在中編譯遠(yuǎn)程模板的可能性,最后得出了兩種方法異步組件,應(yīng)該是官方的推薦方法動(dòng)態(tài)組件,變通之法,論壇上發(fā)現(xiàn)的思路當(dāng)然如果有其他方法歡迎交流,本文如果有不嚴(yán)謹(jǐn)不正確的地方也歡迎指出本文發(fā)自我的,原文鏈接我的 說明 有些時(shí)候你可能需要從后臺(tái)獲取模板,并在前臺(tái)在自己編譯,這在用 AngularJS 1.x 的時(shí)候似乎很常見,可以直接用 ng-include...

    2i18ns 評(píng)論0 收藏0
  • 使用Webpack的代碼分離實(shí)現(xiàn)Vue加載(譯文)

    摘要:當(dāng)一個(gè)的項(xiàng)目體積變得十分龐大的時(shí)候,使用的代碼分離功能將,或的代碼進(jìn)行分離并按需加載,會(huì)極大的提高的首屏加載速度。如果我們使用函數(shù)在中返回模塊作為載荷,就實(shí)現(xiàn)了懶加載。 當(dāng)一個(gè)Vue的項(xiàng)目體積變得十分龐大的時(shí)候,使用Webpack的代碼分離功能將Vue Components,routes或Vuex的代碼進(jìn)行分離并按需加載,會(huì)極大的提高App的首屏加載速度。 showImg(https:...

    SmallBoyO 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<