vue多页面项目开发实战指南

单页应用和多页应用

单页应用

SPA(single page application): 单页面应用,即一个web项目就只有一个页面(即一个HTML文件)。

就是把整个项目的所有页面的所有内容分成了很多的小块(就是组件),可以重复利用的,可以任意调整的组件,每个组件就是一个独立的部分(包括html,css和javascript代码)。再做一个html(基本上啥也没有),这个html就是一个页面容器,需要放哪个组件时,直接引入就行。跳转时,直接跳转组件就行。当需要加载某个组件时,js会动态创建这些组件里的HTML,CSS。

这类项目通常都需要router来进行页面跳转.

一开始只需要加载一次js、css的相关资源。所有内容都包含在主页面,对每一个功能模块组件化。单页应用跳转,就是切换相关组件,仅仅刷新局部资源。

打包后的页面dist 目录结构

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

多页应用

MPA(multipage application): 多页面应用,即一个web项目就有多个页面(即多个HTML文件)。

指有多个独立页面的应用(多个html页面),每个页面必须重复加载js、css等相关资源。多页应用跳转,需要整页资源刷新。

项目是由多个完整的页面组成。多页面跳转刷新所有资源,每个公共资源(js、css等)需选择性重新加载。

打包后的页面dist 目录结构

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

优缺点

单页应用的优缺点

优点
有良好的交互体验。能提升页面切换体验,用户在访问应用页面是不会频繁的去切换浏览页面,从而避免了页面的重新加载。
单页面是一次性把web应用的所有代码(HTML,JavaScript和CSS)全部请求过来,有时候考虑到首屏加载太慢会按需加载。这样一来,以后用户的每一个动作都不会重新加载页面(即不用再问服务器要页面的HTML慢,css和js代码),取而代之的是利用 JavaScript 动态的变换HTML的内容(这不需要和服务器交互,除非数据是动态,那么只需要问服务器要数据即可)。

缺点
SEO难度较高。
首屏加载(初次加载)耗时多。为实现单页Web应用功能及显示效果,需要在加载页面的时候将JavaScript、CSS统一加载,部分页面可以在需要的时候加载。所以必须对JavaScript及CSS代码进行合并压缩处理;

多页应用的优缺点
优点
有利于seo。
首屏加载加载快。

缺点
页面切换慢。资源共用(html、css,js)不共享,不共用,每个页面都需要加载。
页面重复代码多。

配置多页应用

1. 修改vue.config.js

官网配置入口

在 multi-page 模式下构建应用。每个“page”应该有一个对应的 JavaScript 入口文件。其值应该是一个对象,对象的 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',
      // 当使用 title 选项时,
      // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
      title: 'Index Page',
      // 在这个页面中包含的块,默认情况下会包含
      // 提取出来的通用 chunk 和 vendor chunk。
      chunks: ['chunk-vendors', 'chunk-common', 'index']
    },
    // 当使用只有入口的字符串格式时,
    // 模板会被推导为 `public/subpage.html`
    // 并且如果找不到的话,就回退到 `public/index.html`。
    // 输出文件名会被推导为 `subpage.html`。
    subpage: 'src/subpage/main.js'
  }
}

以上是官网的例子,这里我们改写一下,统一配置多页

前提条件在src 下新建一个pages文件夹

pages新建如下三个文件

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

// 这里是遍历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
 
  // 这里是给每个页面设置标题,需要在indexApp.vue设置一个变量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,如果要设置标题的话,需要每个页面都有一个html模版,如果不需要,就可以使用同一个,看个人习惯
  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都是一样的,复制即可

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

3. 合并第三方库

如果不设置分包,所有node_modules 里面的第三方资源库,例如Echarts,Axios,ali-oss,等等都会被打进chunk-vendors,至于为什么会打进去,我们看下vue.config.js默认的分包规则

官网分包splitChunks入口

官网默认的配置

module.exports = {
  //...
 //...
  optimization: {
    splitChunks: {
      chunks: 'async', // 代码分割时对异步代码生效,all:所有代码有效,inital:同步代码有效
      minSize: 30000, // 代码分割最小的模块大小,引入的模块大于 30000B 才做代码分割
      maxSize: 0, // 代码分割最大的模块大小,大于这个值要进行代码分割,一般使用默认值
      minChunks: 1, // 引入的次数大于等于1时才进行代码分割
      maxAsyncRequests: 6, // 最大的异步请求数量,也就是同时加载的模块最大模块数量
      maxInitialRequests: 4, // 入口文件做代码分割最多分成 4 个 js 文件
      automaticNameDelimiter: '~', // 文件生成时的连接符
      automaticNameMaxLength: 30, // 自动生成的文件名的最大长度
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/, // 位于node_modules中的模块做代码分割
          priority: -10 // 根据优先级决定打包到哪个组里,例如一个 node_modules 中的模块进行代码
        }, // 分割,,既满足 vendors,又满足 default,那么根据优先级会打包到 vendors 组中。
        default: { // 没有 test 表明所有的模块都能进入 default 组,但是注意它的优先级较低。
          priority: -20, //  根据优先级决定打包到哪个组里,打包到优先级高的组里。
          reuseExistingChunk: true // //如果一个模块已经被打包过了,那么再打包时就忽略这个上模块
        }
      }
    }
  }
};

我们重点看下 minChunks 这个配置,默认大于1次就会进行分包操作,以前是一个单页面,所以分包没有问题,只会在index.html引入,现在是多页面,每个页面都会引入这个chunk-vendors,有些包其实只有两三个页面用到,因此,最好是不分包,或者达到一定次数才有分包意义

我们这里设置8次,才分包,几乎没有分包,根据各位需求可以自己设置

    optimization: {
      minimize: false,
      splitChunks: {
        cacheGroups: {// 缓存分组
          common: {// 公共的模块
            name: 'chunk-common',//命名要和上面chunks定义的一致
            chunks: 'initial',
            minSize: 1,// 大小限制
            priority: 0,
            minChunks: 8,// 最少复用过几次
          },
          // 打包第三方库的文件
          vendor: {
            name: 'chunk-vendors',//命名要和上面chunks定义的一致
            test: /[\\/]node_modules[\\/]/,
            chunks: 'initial',
            priority: 10,// 权限更高,优先抽离,重要!!!
            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. 其它常见设置

就是一些常见设置,看个人设置 这里重点推荐一下filenameHashing,多页面应用不带hash的设置,因为没有使用路由,也就用不到了.

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'));
  },
  // 关闭eslint校验
  lintOnSave: false,
  // 不生成map文件
  productionSourceMap: false,
  //文件名称不带hash值
  filenameHashing: false,
  devServer: {
    publicPath: '/fund/',
    proxy: {// 本地调试转发
      '/api': {
        target: 'http://127.0.0.1:8080',
        changeOrigin: true,
        pathRewrite: {
          '^/api': '',
        },
      },
    },
  },
};

总结

到此这篇关于vue多页面项目开发的文章就介绍到这了,更多相关vue多页面项目开发内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

  • vuex页面刷新数据丢失问题的四种解决方式
  • Vue页面内公共的多类型附件图片上传区域并适用折叠面板(示例代码)
  • vue如何实现跨页面传递与接收数组并赋值
  • vue实现弹窗引用另一个页面窗口
  • vue跳转页面打开新窗口,并携带与接收参数方式
  • 分布式医疗挂号系统之搭建后台管理系统页面
张贴在2