日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無先后,達者為師

網(wǎng)站首頁 Vue 正文

vue多頁面項目開發(fā)實戰(zhàn)指南_vue.js

作者:孤山漸青 ? 更新時間: 2022-04-01 Vue

單頁應(yīng)用和多頁應(yīng)用

單頁應(yīng)用

SPA(single page application): 單頁面應(yīng)用,即一個web項目就只有一個頁面(即一個HTML文件)。

就是把整個項目的所有頁面的所有內(nèi)容分成了很多的小塊(就是組件),可以重復(fù)利用的,可以任意調(diào)整的組件,每個組件就是一個獨立的部分(包括html,css和javascript代碼)。再做一個html(基本上啥也沒有),這個html就是一個頁面容器,需要放哪個組件時,直接引入就行。跳轉(zhuǎn)時,直接跳轉(zhuǎn)組件就行。當(dāng)需要加載某個組件時,js會動態(tài)創(chuàng)建這些組件里的HTML,CSS。

這類項目通常都需要router來進行頁面跳轉(zhuǎn).

一開始只需要加載一次js、css的相關(guān)資源。所有內(nèi)容都包含在主頁面,對每一個功能模塊組件化。單頁應(yīng)用跳轉(zhuǎn),就是切換相關(guān)組件,僅僅刷新局部資源。

打包后的頁面dist 目錄結(jié)構(gòu)

dist
├── static
│   ├── css
│   ├── js
│   ├── img
│   ├── dll
│   └── ...
└── index.html
└── ...
└── ...

多頁應(yīng)用

MPA(multipage application): 多頁面應(yīng)用,即一個web項目就有多個頁面(即多個HTML文件)。

指有多個獨立頁面的應(yīng)用(多個html頁面),每個頁面必須重復(fù)加載js、css等相關(guān)資源。多頁應(yīng)用跳轉(zhuǎn),需要整頁資源刷新。

項目是由多個完整的頁面組成。多頁面跳轉(zhuǎn)刷新所有資源,每個公共資源(js、css等)需選擇性重新加載。

打包后的頁面dist 目錄結(jié)構(gòu)

dist
├── page(這里名字打包出哪個文件夾自己配置)
│   ├── css
│   ├── js
│   ├── img
│   ├── index.html
│   └── user.html
│   └── setting.html
│   └── ....html
│   └── ....html
.   ....
.   ....
.   ....

優(yōu)缺點

單頁應(yīng)用的優(yōu)缺點

優(yōu)點
有良好的交互體驗。能提升頁面切換體驗,用戶在訪問應(yīng)用頁面是不會頻繁的去切換瀏覽頁面,從而避免了頁面的重新加載。
單頁面是一次性把web應(yīng)用的所有代碼(HTML,JavaScript和CSS)全部請求過來,有時候考慮到首屏加載太慢會按需加載。這樣一來,以后用戶的每一個動作都不會重新加載頁面(即不用再問服務(wù)器要頁面的HTML慢,css和js代碼),取而代之的是利用 JavaScript 動態(tài)的變換HTML的內(nèi)容(這不需要和服務(wù)器交互,除非數(shù)據(jù)是動態(tài),那么只需要問服務(wù)器要數(shù)據(jù)即可)。

缺點
SEO難度較高。
首屏加載(初次加載)耗時多。為實現(xiàn)單頁Web應(yīng)用功能及顯示效果,需要在加載頁面的時候?qū)avaScript、CSS統(tǒng)一加載,部分頁面可以在需要的時候加載。所以必須對JavaScript及CSS代碼進行合并壓縮處理;

多頁應(yīng)用的優(yōu)缺點
優(yōu)點
有利于seo。
首屏加載加載快。

缺點
頁面切換慢。資源共用(html、css,js)不共享,不共用,每個頁面都需要加載。
頁面重復(fù)代碼多。

配置多頁應(yīng)用

1. 修改vue.config.js

官網(wǎng)配置入口

在 multi-page 模式下構(gòu)建應(yīng)用。每個“page”應(yīng)該有一個對應(yīng)的 JavaScript 入口文件。其值應(yīng)該是一個對象,對象的 key 是入口的名字,value 是:

  • 一個指定了 entry, template, filename, title 和 chunks 的對象 (除了 entry 之外都是可選的);
  • 或一個指定其 entry 的字符串。
module.exports = {
  pages: {
    index: {
      // page 的入口
      entry: 'src/index/main.js',
      // 模板來源
      template: 'public/index.html',
      // 在 dist/index.html 的輸出
      filename: 'index.html',
      // 當(dāng)使用 title 選項時,
      // template 中的 title 標簽需要是 <title><%= htmlWebpackPlugin.options.title %></title>
      title: 'Index Page',
      // 在這個頁面中包含的塊,默認情況下會包含
      // 提取出來的通用 chunk 和 vendor chunk。
      chunks: ['chunk-vendors', 'chunk-common', 'index']
    },
    // 當(dāng)使用只有入口的字符串格式時,
    // 模板會被推導(dǎo)為 `public/subpage.html`
    // 并且如果找不到的話,就回退到 `public/index.html`。
    // 輸出文件名會被推導(dǎo)為 `subpage.html`。
    subpage: 'src/subpage/main.js'
  }
}

以上是官網(wǎng)的例子,這里我們改寫一下,統(tǒng)一配置多頁

前提條件在src 下新建一個pages文件夾

pages新建如下三個文件

pages
└── index-skeleton.html
└── indexApp.html
└── app.js
const glob = require('glob')
const fs = require('fs');
let titleObj = {};
// 統(tǒng)一配置多頁

// 這里是遍歷src下面的pages 下面每個文件夾(例如index)下以xxxApp.vue 命名的vue頁面
glob.sync('./src/pages/**/*App.vue').forEach((path) => {
    // 遍歷path
    console.log(path,'path')
   //./src/pages/index/indexApp.vue path
  
  // 找到文件名
  const fileName = path.split('/')[path.split('/').length - 1];
   console.log(fileName,'fileName')
   // indexApp.vue fileName
  
  // 去掉App 后綴
  const chunk = path.substring(12, path.indexOf('/' + fileName));
    console.log(chunk,'chunk')
   // index chunk
 
  // 這里是給每個頁面設(shè)置標題,需要在indexApp.vue設(shè)置一個變量pageTitle
  let fileContent = fs
    .readFileSync(path, { encoding: 'utf-8' })
    .toString()
    .replace(/\r\n/g, '');
  fileContent = fileContent.substr(fileContent.indexOf('pageTitle:'));
  fileContent = fileContent.substr(0, fileContent.indexOf(','));

  fileContent =
    fileContent.indexOf('"') > 0
      ? fileContent.substr(fileContent.indexOf('"') + 1)
      : fileContent.substr(fileContent.indexOf("'") + 1);

  fileContent =
    fileContent.indexOf('"') > 0
      ? fileContent.substr(0, fileContent.indexOf('"'))
      : fileContent.substr(0, fileContent.indexOf("'"));
  titleObj[chunk] = fileContent ? fileContent : '標題';
});


// 這里是遍歷src下面的pages 下面每個文件夾(例如index)下以app.js
glob.sync('./src/pages/**/app.js').forEach((path) => {
  //打包js
  const chunk = path.split('./src/pages/')[1].split('/app.js')[0];
  const tmp = chunk.split('/');
  // 模版html,如果都是一樣的,可以直接使用public下index.html,如果要設(shè)置標題的話,需要每個頁面都有一個html模版,如果不需要,就可以使用同一個,看個人習(xí)慣
  let templateUrl =
    'src/pages/' + chunk + '/' + tmp[tmp.length - 1] + '-skeleton.html';

  pages[chunk] = {
    entry: path,//入口文件
    template: templateUrl,//模版html
    title: titleObj[chunk] ? titleObj[chunk] : '標題',//標題
    filename: chunk.replace(/\//g, '-') + '.html',//打包出來的html名字
    chunks: ['chunk-vendors', 'chunk-common', chunk],//依賴包
  };
});
module.exports = {
  // 選項...
  publicPath: process.env.NODE_ENV === 'production'
    ? '/dist/'
    : '/',
  pages,
}

2. 修改title

其實是用插件替換的

很簡單,就是把html模版中的title使用模版語法就行

例如index-skeleton.html 這里每個頁面html都是一樣的,復(fù)制即可

<title><%= htmlWebpackPlugin.options.title %></title>

3. 合并第三方庫

如果不設(shè)置分包,所有node_modules 里面的第三方資源庫,例如Echarts,Axios,ali-oss,等等都會被打進chunk-vendors,至于為什么會打進去,我們看下vue.config.js默認的分包規(guī)則

官網(wǎng)分包splitChunks入口

官網(wǎng)默認的配置

module.exports = {
  //...
 //...
  optimization: {
    splitChunks: {
      chunks: 'async', // 代碼分割時對異步代碼生效,all:所有代碼有效,inital:同步代碼有效
      minSize: 30000, // 代碼分割最小的模塊大小,引入的模塊大于 30000B 才做代碼分割
      maxSize: 0, // 代碼分割最大的模塊大小,大于這個值要進行代碼分割,一般使用默認值
      minChunks: 1, // 引入的次數(shù)大于等于1時才進行代碼分割
      maxAsyncRequests: 6, // 最大的異步請求數(shù)量,也就是同時加載的模塊最大模塊數(shù)量
      maxInitialRequests: 4, // 入口文件做代碼分割最多分成 4 個 js 文件
      automaticNameDelimiter: '~', // 文件生成時的連接符
      automaticNameMaxLength: 30, // 自動生成的文件名的最大長度
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/, // 位于node_modules中的模塊做代碼分割
          priority: -10 // 根據(jù)優(yōu)先級決定打包到哪個組里,例如一個 node_modules 中的模塊進行代碼
        }, // 分割,,既滿足 vendors,又滿足 default,那么根據(jù)優(yōu)先級會打包到 vendors 組中。
        default: { // 沒有 test 表明所有的模塊都能進入 default 組,但是注意它的優(yōu)先級較低。
          priority: -20, //  根據(jù)優(yōu)先級決定打包到哪個組里,打包到優(yōu)先級高的組里。
          reuseExistingChunk: true // //如果一個模塊已經(jīng)被打包過了,那么再打包時就忽略這個上模塊
        }
      }
    }
  }
};

我們重點看下 minChunks 這個配置,默認大于1次就會進行分包操作,以前是一個單頁面,所以分包沒有問題,只會在index.html引入,現(xiàn)在是多頁面,每個頁面都會引入這個chunk-vendors,有些包其實只有兩三個頁面用到,因此,最好是不分包,或者達到一定次數(shù)才有分包意義

我們這里設(shè)置8次,才分包,幾乎沒有分包,根據(jù)各位需求可以自己設(shè)置

    optimization: {
      minimize: false,
      splitChunks: {
        cacheGroups: {// 緩存分組
          common: {// 公共的模塊
            name: 'chunk-common',//命名要和上面chunks定義的一致
            chunks: 'initial',
            minSize: 1,// 大小限制
            priority: 0,
            minChunks: 8,// 最少復(fù)用過幾次
          },
          // 打包第三方庫的文件
          vendor: {
            name: 'chunk-vendors',//命名要和上面chunks定義的一致
            test: /[\\/]node_modules[\\/]/,
            chunks: 'initial',
            priority: 10,// 權(quán)限更高,優(yōu)先抽離,重要!!!
            minChunks: 8,
          },
        },
      },
    },

4. 打包第三方scss

有一些自己寫的公共scss,比如common.scss ,不想在頁面引入,因為每個頁面都要引入,其實也有很簡單處理的方法,這和以前沒什么變化,話不多說,直接上代碼

let scssVariables = require('./src/scss/variables.scss.js');

css: {
    loaderOptions: {
      scss: {
        prependData:
          Object.keys(scssVariables)
            .map((k) => `${k.replace('_', '-')}: ${scssVariables[k]};`)
            .join('\n') + '\n',
      },
    },
  },

5. 其它常見設(shè)置

就是一些常見設(shè)置,看個人設(shè)置 這里重點推薦一下filenameHashing,多頁面應(yīng)用不帶hash的設(shè)置,因為沒有使用路由,也就用不到了.

module.exports = {
  publicPath: './',
  //輸出目錄
  outputDir: 'fund',
  assetsDir: '',
  // 配置別名
  chainWebpack: (config) => {
    config.resolve.alias.set('@', resolve('src'));
    config.resolve.alias.set('@@', resolve('src/components'));
    config.resolve.alias.set('@assets', resolve('src/assets'));
    config.resolve.alias.set('scss', resolve('src/scss'));
  },
  // 關(guān)閉eslint校驗
  lintOnSave: false,
  // 不生成map文件
  productionSourceMap: false,
  //文件名稱不帶hash值
  filenameHashing: false,
  devServer: {
    publicPath: '/fund/',
    proxy: {// 本地調(diào)試轉(zhuǎn)發(fā)
      '/api': {
        target: 'http://127.0.0.1:8080',
        changeOrigin: true,
        pathRewrite: {
          '^/api': '',
        },
      },
    },
  },
};

總結(jié)

原文鏈接:https://juejin.cn/post/7054439846927925256

欄目分類
最近更新