vue多页面应用配置

首先搭建一个脚手架项目,vuecli4 + vue2默认配置 + router + vuex。此时得到一个原始的vue单页面应用项目,去掉组件。

多页面应用结构

了解单页面

在项目根目录下新建vue.config.js文件,我们先看看默认配置了解一下单页应用

image-20201027173459149

module.exports = {
  publicPath: "/",
  productionSourceMap: false,
  // 页面入口
  pages:{
    index: {
      entry: "src/main.js",
      title: "标题",
    },
  },
  devServer: {
    open: false, //关闭自动打开浏览器
  }
 }

此时打包后的index.html会使用main.js作为入口,可以理解为初始化的执行文件

当然,我们不想让他叫index.html,给他换个名字是吧,比如demo.html

我们修改一下页面对象的名字,如下

module.exports = {
  publicPath: "/",
  productionSourceMap: false,
  // 页面入口
  pages:{
    demo: {
      entry: "src/main.js",
      title: "标题",
    },
  },
  devServer: {
    open: false, //关闭自动打开浏览器
  }
 }

此时打包后的页面文件为demo.html,它会使用main.js作为入口

当然,我们可能还要加入模板页面,打包的时候以它为模板

我们在根目录新建一个HTML文件,就叫template.html

<!DOCTYPE html>
<html>
<head>
    <meta charset=utf-8>
    <meta name=viewport content="width=device-width,initial-scale=1">
    <title>
        <%= htmlWebpackPlugin.options.title %>
    </title>
</head>

<body>
  <div id=app></div>
</body>

</html>

<%= htmlWebpackPlugin.options.title %>对应的是页面对象的title属性,当然还有其他一些属性

此时,vue.config.js需要修改一下

module.exports = {
  publicPath: "/",
  productionSourceMap: false,
  // 页面入口
  pages:{
    index: {
      entry: "src/main.js",
      // 模板文件
      template: "template.html",
      // 在 dist/index.html 的输出
      filename: "index.html",
      // 当使用 title 选项时,
      // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
      title: "标题",
    },
  },
  devServer: {
    open: false, //关闭自动打开浏览器
  }
 }

此时打包后会输出index.html文件

问题来了,修改页面对象的名字跟页面对象中的filename属性有什么关系呢?

我认为在filename为空的情况下,打包时会使用页面对象的名字

总的来说,就是filename属性优先

这么一来,vue单页面应用的结构好像摸得差不多了

访问HTML文件,然后通过入口JS文件进行初始化(如实例化Vue),把App.vue挂到网页上

基于单页面改造多页面

基于单页面应用,如何改造成多页面应用?

上面我们知道,一个Vue单页面应用入口由三部分组成:网页模板.html、入口文件.js、Vue页面.vue

网页模板不是必须提供的,但打包时会生成默认的模板

那么每一个页面都是这样子的咯,我们开始改造?

image-20201027181144590

根据两个页面对象的filename,我们知道打包后是两个页面文件app1.htmlapp2.html

index.html是什么?

image-20201027181312761

可以看到index.html里面并没有逻辑代码,所以纯粹就是输出了一个默认的网页模板

打开浏览器,看下我们的成果

image-20201027181619615

多页面应用get!!!

多页面应用中各页面是相互独立的, 因为他们各自拥有自己的Vue实例和router实例和vuex实例

可以说是两个独立的项目

自动生成页面对象

const glob = require("glob");
// 获取文件信息 => 生成pages对象
function handleEntry(entry) {
  const entries = {};
  let entryBaseName = "";
  let entryPathName = "";
  let entryTemplate = "";

  glob.sync(entry).forEach(item => {
    entryBaseName = path.basename(item, path.extname(item));
    entryTemplate = item.split("/").splice(-3);
    entryPathName = entryBaseName;
    /**
     * entry为pages下页面文件夹名字的js文件,如pages/app1/app1.js
     * template为pages下页面文件夹的html文件
     */
    entries[entryPathName] = {
      entry: `src/${entryTemplate[0]}/${entryTemplate[1]}/${entryTemplate[1]}.js`,
      template: `src/${entryTemplate[0]}/${entryTemplate[1]}/${entryTemplate[2]}`,
      title: entryTemplate[2],
      filename: entryTemplate[2],
    };
  });

  return entries;
}

const pages = handleEntry("./src/pages/**?/*.html"); // 调用函数扫描pages文件夹


module.exports = {
	pages,
}

注意: 用此方法生成页面对象时必须保证pages下文件夹与相应入口js文件同名, 如pages/app1/app1.js

隐藏html后缀

然后我们兴奋地打包文件部署到生产环境Nginx上,然后访问

image-20201027183545808

一脸问号???那我们换个方式....

index.html 是默认网页,在服务器上比如访问'/'时,服务器会指向index.html。故不会发生这种情况

image-20201027183640128

啊这...每次都要加个html后缀才能访问,甲方会不会炸的?

注意:路由模式为History的请往下看,此方法不适用

我们配置一下nginx让他在没有后缀名的情况下也能找到文件,配置文件为XX.conf

 location / {
     if (!-f $request_filename){
         rewrite (.*)$ $1.html last;
         break;
     }
 }

大功告成

注意: 在隐藏html后缀的情况下,url不允许"."的出现; 即参数不能出现点, 同时页面跳转无需加后缀<a href="./app2"></a>

路由使用history

甲方可能又要说了:你这个网址怎么每次都有一个#呀,去掉去掉

噢!万能的工具人此时应该想到了路由里面的mode: "history"

我们把路由改成history模式,热情高涨地进行开发

路由跳转路径有误

尝试切换路由,不对劲 => /app1应该切换到/app1/about的,但实际上是切成/about

好活!路由加个前缀应该就没问题了

const router = new VueRouter({
  mode: "history",
  base:"/app1/",
  routes
})

刷新路由丢失

开发环境中,路由跳转后刷新页面可能会出现404错误。因为刷新页面时访问的资源找不到,因为vue-router设置的路径不是真实存在的路径。vue.config.js加入以下配置

  devServer: {
    open: false, //关闭自动打开浏览器
    historyApiFallback: {
      verbose: true,
      rewrites: [
        { from: /^\/app1\/.*$/, to: "/app1.html" },
        { from: /^\/app2\/.*$/, to: "/app2.html" },
      ],
    },
  }

既然本地开发的服务端要做配置,那么生产环境的nginx服务器也需配置

location / {
    try_files $uri $uri/ @router;
    index index.html;
}


location @router {
    # rewrite ^.*$ /index.html  last;
    # 多页面 时刷新配置如下 
    # rewrite ^((?!/(app1|app2)/*).)*$ /index.html last; 
    rewrite ^/app1/*  /app1.html  last;
    rewrite ^/app2/*  /app2.html  last;
}

其他错误

Uncaught SyntaxError:Unexpected token

vue.config.js配置

module.exports = {
  publicPath: "/",
}