今天就跟大家聊聊有關(guān)怎么在Vue中動(dòng)態(tài)加載異步組件,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
成都創(chuàng)新互聯(lián)于2013年開(kāi)始,先為房縣等服務(wù)建站,房縣等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為房縣企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。背景:
目前我們項(xiàng)目都是按組件劃分的,然后各個(gè)組件之間封裝成產(chǎn)品。目前都是采用iframe直接嵌套頁(yè)面。項(xiàng)目中我們還是會(huì)碰到一些通用的組件跟業(yè)務(wù)之間有通信,這種情況下iframe并不是最好的選擇,iframe存在跨域的問(wèn)題,當(dāng)然是postMessage還是可以通信的,但也并非是最好的。目前有這么一個(gè)場(chǎng)景:門(mén)戶需要制作通用的首頁(yè)和數(shù)據(jù)概覽頁(yè)面,首頁(yè)和數(shù)據(jù)概覽頁(yè)面通過(guò)小部件來(lái)自由拼接。業(yè)務(wù)組件在制作的時(shí)候只需要提供各個(gè)模塊小部件的url就可以了,可是如果小部件之間還存在聯(lián)系呢?那么iframe是不好的。目前采用Vue動(dòng)態(tài)加載異步組件的方式來(lái)實(shí)現(xiàn)小組件之間的通信。當(dāng)然門(mén)戶也要提供一個(gè)通信的基線:Vue事件總線(空的Vue實(shí)例對(duì)象)。
內(nèi)容:
使用過(guò)vue的都應(yīng)該知道vue的動(dòng)態(tài)加載組件components:
Vue通過(guò)is來(lái)綁定需要加載的組件。那么我們現(xiàn)在需要的就是如何打包組件,如果通過(guò)復(fù)制業(yè)務(wù)組件內(nèi)部的代碼,那么這種就需要把依賴全部找齊,并復(fù)制過(guò)去(很多情況下會(huì)漏下某個(gè)圖片或css等),這種方式是比較low的,不方便維護(hù)。因此我們需要通過(guò)webpack來(lái)打包單個(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 }) + '\n\n') if (stats.hasErrors()) { console.log(chalk.red(' Build failed with errors.\n')) process.exit(1) } console.log(chalk.cyan(' Build complete.\n')) console.log(chalk.yellow( ' Tip: built files are meant to be served over an HTTP server.\n' + ' Opening index.html over file:// won\'t work.\n' )) })
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 自身異步組件寫(xiě)法以及 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是工具庫(kù),這邊是打包的entry自動(dòng)獲?。J(rèn)為src/out-components),還有自動(dòng)刪除之前打包的文件。
目前的文件目錄為
通過(guò)打包生產(chǎn)文件:
在static下outComponents文件夾內(nèi)的js文件。(最終打包需要打包到dist下面,這邊做測(cè)試先打包在static文件下,方便后續(xù)動(dòng)態(tài)組件ajax獲取組件使用)
門(mén)戶的小部件是通過(guò)配置url,和調(diào)整布局來(lái)生產(chǎn)的。因此業(yè)務(wù)組件至此已經(jīng)完成了。只需要提供對(duì)門(mén)戶暴露的url即可。
接下來(lái)就是門(mén)戶這邊加載動(dòng)態(tài)組件的實(shí)現(xiàn)了。門(mén)戶這邊就相對(duì)簡(jiǎn)單了??慈缦聢D配置:
門(mén)戶通過(guò)component的動(dòng)態(tài)組件來(lái)實(shí)現(xiàn)加載異步組件,通過(guò)ajax請(qǐng)求剛才打包的url,然后實(shí)例化函數(shù)new Function來(lái)賦值給mode(new Function之所以分成2部,是因此效驗(yàn)規(guī)則的問(wèn)題,可忽略)。這樣就實(shí)現(xiàn)了動(dòng)態(tài)加載異步組件了。門(mén)戶和業(yè)務(wù)組件可以各個(gè)開(kāi)發(fā),任何業(yè)務(wù)開(kāi)發(fā)數(shù)據(jù)概覽,門(mén)戶都不需要改代碼,只需要界面上配置url即可。這個(gè)異步加載組件已經(jīng)結(jié)束了。這邊門(mén)戶需要封裝一封實(shí)現(xiàn)異步組件。父級(jí)只需要傳入url即可。這邊還有個(gè)可以優(yōu)化的是,可以把mode優(yōu)先緩存,那么不需要每次都去加載請(qǐng)求。如下:
我們可以看到在門(mén)戶的一個(gè)數(shù)據(jù)概覽頁(yè)面上加載了多個(gè)異步組件,那么異步組件之間也是可能存在通信的,這樣該如何做呢?因?yàn)楝F(xiàn)在已經(jīng)不是iframe嵌套了,可以通過(guò)監(jiān)聽(tīng)一個(gè)組件,然調(diào)用另一個(gè)組件的方法,這樣確實(shí)可以實(shí)現(xiàn)平級(jí)組件間的通信,但這樣勢(shì)必不可取的,因?yàn)橐坏┻@樣做了門(mén)戶必須要根據(jù)業(yè)務(wù)來(lái)輔助,修改代碼來(lái)實(shí)現(xiàn)功能。因此這邊借用門(mén)戶來(lái)生成vue事件總線(空的vue實(shí)例)來(lái)實(shí)現(xiàn)。
門(mén)戶代碼如下: 在this.$root上掛在一個(gè)事件總線:
created () { if (!this.$root.eventBus) { this.$root.eventBus = new Vue() } }
然后業(yè)務(wù)組件之間就可以根據(jù)自己的業(yè)務(wù)實(shí)現(xiàn)通信:
組件一和組件二代碼如下:
<template> <div class="test1"> 這是一個(gè)外部組件a1 <hello-word></hello-word> </div> </template> <script> import helloWord from '../components/HelloWorld' export default { data () { return { i: 0 } }, components: { helloWord }, mounted () { setInterval(() => { this.i++ if (this.i < 10) { this.test() } }, 1000) }, methods: { test () { this.$root.eventBus.$emit('childEvent', this.i) } } } </script>
<template> <div class="test1"> 這也是外部組件哦 <div > 這是a1傳來(lái)的{{a1}} </div> </div> </template> <script> export default { data () { return { a1: 0 } }, created () { this.$root.eventBus.$on('childEvent', this.change) }, methods: { change (i) { this.a1 = i } } } </script>
為什么要使用Vue
Vue是一款友好的、多用途且高性能的JavaScript框架,使用vue可以創(chuàng)建可維護(hù)性和可測(cè)試性更強(qiáng)的代碼庫(kù),Vue允許可以將一個(gè)網(wǎng)頁(yè)分割成可復(fù)用的組件,每個(gè)組件都包含屬于自己的HTML、CSS、JavaScript,以用來(lái)渲染網(wǎng)頁(yè)中相應(yīng)的地方,所以越來(lái)越多的前端開(kāi)發(fā)者使用vue。
看完上述內(nèi)容,你們對(duì)怎么在Vue中動(dòng)態(tài)加載異步組件有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。
網(wǎng)頁(yè)題目:怎么在Vue中動(dòng)態(tài)加載異步組件-創(chuàng)新互聯(lián)
文章起源:http://jinyejixie.com/article20/hgoco.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供搜索引擎優(yōu)化、電子商務(wù)、靜態(tài)網(wǎng)站、自適應(yīng)網(wǎng)站、網(wǎng)站制作、企業(yè)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容
移動(dòng)網(wǎng)站建設(shè)知識(shí)