手把手帶你把vue+webpack 單頁面改多頁面(適合上手),支持多級目錄

前言

公司做的後臺管理系統,越做越龐大,而且系統之間還需要經常的來回嵌套頁面,單頁面已經不太順手了。
所以我把vue+elementui+webpack單頁面改爲多頁面的經驗在這裏嘮叨嘮叨,這裏作展示的是一個簡單的後臺管理系統,利用iframe模擬的路由跳轉,很簡單也很容易上手,可以把這個項目下載到本地,然後把你們的頁面慢慢移進去,希望能幫到一些小夥伴。

建議,把項目下載下來跑起來,結合着項目看這篇文章,不然會蒙。
gitHub:歡迎各位star
在線預覽:網站不太穩定,最好下載到本地
效果預覽:
圖片描述

思路

一.普遍的實現方案:

1.手動改造webpack,配置多個入口,配置多個出口;
2.每個目錄下邊都有個.html文件來承載實例,.js文件引入Vue等等模塊,.vue頁面來書寫邏輯等,如圖:
clipboard.png

二.改進的方案

1.用node自帶的模塊fs來動態的匹配目錄,動態的生成入口文件,動態的生成打包出口文件;
2.我們寫一個公共的html文件來承載實例,寫一個公共的js來引入各種依賴,根據動態傳入.vue文件模塊生成實例
如圖:

clipboard.png

3.解釋一下template下的config.js:
因爲我們現在只用config.js來去引入各種依賴,就像單頁面的mian.js一樣,不同的是,
需要被掛載的vue文件是動態的,所以我們用localStorage來傳遞,我們在頁面目錄下邊只用寫一個.vue文件,一個.js文件,
這個.js文件裏只用寫上當前對應的.vue文件所在的目錄,不用在每個js裏寫那麼多引入的依賴

文件目錄下的js:

let baseUrl = "china/china"
localStorage.setItem('baseUrl', baseUrl)

template/config.js

// 如果你想用自己創建的實例,在自己單獨的js文件里加上:let baseUrl="noNeed" / localStorage.setItem('baseUrl',baseUrl)
let baseMounted = localStorage.getItem('baseUrl')
console.log(baseMounted)

import '../src/style/index.scss' //公用樣式

if (baseMounted === 'noNeed') {
  // 組件自己創建了實,將不會再引入下邊的資源
  throw new Error("當前組件自己創建了實例,不會引用公用方法、實例");
}
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
// 動態捕獲要掛載實例的.vue文件的路徑
var App = resolve => require.ensure([], () => resolve(require("../src/views/" + baseMounted + ".vue")));
new Vue({
  el: '#app',
  template: '<App/>',
  components: { App }
})

總結:就是你每次切換頁面的時候,會先加載自己目錄下的js文件,js裏用localStorage存儲.vue的路徑(當然你也可以寫成'noNeed',這樣你自己就得在js裏去引入各種依賴了),
再去引用template/config.js的時候,利用localStorage告訴掛載實例的模板是哪個。

三.最重要的webpack配置

webpack的複雜程度我就不累贅了(我自己也是個入門選手),這個需要自己花時間去看,我就直接講下實現的結果。
主要的實現邏輯就是下邊的這個js文件,出處我翻不到了,不知道是哪位大神研究出來的,
這個js文件主要實現了webpack匹配出入口文件的功能,
一開始,我也是研究了研究裏邊的方法,然後在原版的基礎上改造了好幾版,實現了現在的效果,
主要改了公共模板html和js,以及js的加載順序。

build下的這三個文件都要改成multipage-helper.js裏的方法

clipboard.png

multipage-helper.js:

var path = require('path')
var fs = require("fs")
const resolve = (p) => path.resolve(__dirname, "..", p)
var HtmlWebpackPlugin = require('html-webpack-plugin')
const templatePath = resolve("template/index.html")
const templateJs = "./template/config.js"

var moduleList //緩存多頁面模塊列表
var moduleRootPath = './src/views' //模塊根目錄(這個可以根據自己的需求命名)

/**
 * 獲取js入口數組
 */
exports.getEntries = function getEntries() {
  //緩存js入口數組
  var entries = {}
  //初始化模塊列表
  this.getModuleList()
  //變量模塊列表
  moduleList.forEach(function(module) {
    if (module.moduleID != "" && module.moduleJS != "") {
      entries[module.moduleID] = module.moduleJS
    }
  })
  entries.app=templateJs
  console.log("*********************************** entries ***********************************")
  console.log(entries)
  return entries
}

/**
 * 獲取多頁面模塊列表
 * @returns {模塊的信息集合}
 */
exports.getModuleList = function getModuleList() {
  //判斷是否爲空,不爲空則直接返回
  if (moduleList) {
    return moduleList
  } else { //爲空則讀取列表
    moduleList = new Array();
    readDirSync(moduleRootPath, "")
    console.log("*********************************** moduleList ***********************************")
    console.log(moduleList)
    return moduleList
  }
}

/**
 * 獲取dev的Html模板集合
 * @returns {dev的Html模板集合}
 */
exports.getDevHtmlWebpackPluginList = function getDevHtmlWebpackPluginList() {
  console.log("*********************************** devHtmlWebpackPluginList ***********************************")
  //緩存dev的Html模板集合
  var devHtmlWebpackPluginList = []
  //獲取多頁面模塊集合
  var moduleList = this.getModuleList()
  //遍歷生成模塊的HTML模板
  moduleList.forEach(function(mod) {
    //生成配置
    var conf = {
      filename: mod.moduleID + ".html",
      template: mod.moduleHTML ? mod.moduleHTML : templatePath,
      chunks: [mod.moduleID,'app'],
      chunksSortMode: 'manual',
      inject: true
    }
    console.log(conf)
    //添加HtmlWebpackPlugin對象
    devHtmlWebpackPluginList.push(new HtmlWebpackPlugin(conf))
  })
  return devHtmlWebpackPluginList
}

/**
 * 獲取prod的Html模板集合
 * @returns {prod的Html模板集合}
 */
exports.getProdHtmlWebpackPluginList = function getProdHtmlWebpackPluginList() {
  console.log("*********************************** prodHtmlWebpackPluginList ***********************************")
  //緩存dev的Html模板集合
  var prodHtmlWebpackPluginList = []
  //獲取多頁面模塊集合
  var moduleList = this.getModuleList()
  //遍歷生成模塊的HTML模板
  moduleList.forEach(function(mod) {
    //生成配置
    var conf = {
      filename: mod.moduleID + ".html",
      template: mod.moduleHTML ? mod.moduleHTML : templatePath,
      inject: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
        // more options:
        // https://github.com/kangax/html-minifier#options-quick-reference
      },
      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
      chunksSortMode: 'dependency',
      chunks: ['manifest', 'vendor', mod.moduleID,'app'],
      chunksSortMode: 'manual'
    }
    console.log(conf)
    //添加HtmlWebpackPlugin對象
    prodHtmlWebpackPluginList.push(new HtmlWebpackPlugin(conf))
  })
  return prodHtmlWebpackPluginList
}

/**
 * 深度遍歷目錄,並整理多頁面模塊
 * @param path 需要變量的路徑
 * @param moduleName 模塊名稱
 */
function readDirSync(path, moduleName) {
  //緩存模塊對象
  var module = { moduleID: "", moduleHTML: "", moduleJS: "" }
  //獲取當前模塊ID
  var moduleID = path.replace(moduleRootPath + "/", "")
  if (path == moduleRootPath) {
    moduleID = ""
  }
  module.moduleID = moduleID
  //獲取目錄下所有文件及文件夾
  var pa = fs.readdirSync(path)
  pa.forEach(function(ele, index) {
    var info = fs.statSync(path + "/" + ele)
    if (info.isDirectory()) {
      // console.log("dir: "+ele)
      readDirSync(path + "/" + ele, ele)
    } else {
      //判斷當前模塊的html是否存在
      if (moduleName+".html" == ele){
        module.moduleHTML = path+"/"+ele
      }
      // module.moduleHTML = templatePath

      //判斷當前模塊的js是否存在
      if (moduleName + ".js" == ele) {
        module.moduleJS = path + "/" + ele
      }
      // console.log("file: "+ele)
    }
  })
  //判斷模塊是否真實(可能只是個分級目錄)
  if ((module.moduleID != "" && module.moduleHTML != "") || (module.moduleID != "" && module.moduleJS != "")) {
    moduleList.push(module)
  }
}

鄙人的webpack正在學習中,所以可能有些細節講的不會太清楚,但能用,希望大家的指正,也希望能幫到大家,嘻嘻嘻。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章