本文最后更新于:几秒前
首先搭建一个脚手架项目,vuecli4 + vue2默认配置 + router + vuex
。此时得到一个原始的vue单页面应用项目,去掉组件。
多页面应用结构
了解单页面
在项目根目录下新建vue.config.js
文件,我们先看看默认配置了解一下单页应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| module.exports = { publicPath: "/", productionSourceMap: false, pages:{ index: { entry: "src/main.js", title: "标题", }, }, devServer: { open: false, } }
|
此时打包后的index.html
会使用main.js
作为入口,可以理解为初始化的执行文件
当然,我们不想让他叫index.html
,给他换个名字是吧,比如demo.html
我们修改一下页面对象的名字,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| module.exports = { publicPath: "/", productionSourceMap: false, pages:{ demo: { entry: "src/main.js", title: "标题", }, }, devServer: { open: false, } }
|
此时打包后的页面文件为demo.html
,它会使用main.js
作为入口
当然,我们可能还要加入模板页面,打包的时候以它为模板
我们在根目录新建一个HTML文件,就叫template.html
吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <!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
需要修改一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| module.exports = { publicPath: "/", productionSourceMap: false, pages:{ index: { entry: "src/main.js", template: "template.html", filename: "index.html", title: "标题", }, }, devServer: { open: false, } }
|
此时打包后会输出index.html
文件
问题来了,修改页面对象的名字跟页面对象中的filename属性有什么关系呢?
我认为在filename为空的情况下,打包时会使用页面对象的名字
总的来说,就是filename属性优先
这么一来,vue单页面应用
的结构好像摸得差不多了
访问HTML文件,然后通过入口JS文件进行初始化(如实例化Vue),把App.vue
挂到网页上
基于单页面改造多页面
基于单页面应用,如何改造成多页面应用?
上面我们知道,一个Vue单页面应用
入口由三部分组成:网页模板.html
、入口文件.js
、Vue页面.vue
网页模板不是必须提供的,但打包时会生成默认的模板
那么每一个页面都是这样子的咯,我们开始改造?
根据两个页面对象的filename
,我们知道打包后是两个页面文件app1.html
和app2.html
那index.html
是什么?
可以看到index.html
里面并没有逻辑代码,所以纯粹就是输出了一个默认的网页模板
打开浏览器,看下我们的成果
多页面应用get!!!
多页面应用中各页面是相互独立的, 因为他们各自拥有自己的Vue实例和router实例和vuex实例
可以说是两个独立的项目
自动生成页面对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| const glob = require("glob");
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;
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");
module.exports = { pages, }
|
注意: 用此方法生成页面对象时必须保证pages下文件夹与相应入口js文件同名, 如pages/app1/app1.js
隐藏html后缀
然后我们兴奋地打包文件部署到生产环境Nginx
上,然后访问
一脸问号???那我们换个方式….
index.html 是默认网页,在服务器上比如访问’/‘时,服务器会指向index.html。故不会发生这种情况
啊这…每次都要加个html后缀才能访问,甲方会不会炸的?
注意:路由模式为History的请往下看,此方法不适用
我们配置一下nginx
让他在没有后缀名的情况下也能找到文件,配置文件为XX.conf
1 2 3 4 5 6
| location / { if (!-f $request_filename){ rewrite (.*)$ $1.html last; break; } }
|
大功告成
注意: 在隐藏html后缀的情况下,url不允许”.”的出现; 即参数不能出现点, 同时页面跳转无需加后缀<a href="./app2"></a>
路由使用history
甲方可能又要说了:你这个网址怎么每次都有一个#
呀,去掉去掉
噢!万能的工具人此时应该想到了路由里面的mode: "history"
我们把路由改成history
模式,热情高涨地进行开发
路由跳转路径有误
尝试切换路由,不对劲 => /app1
应该切换到/app1/about
的,但实际上是切成/about
好活!路由加个前缀应该就没问题了
1 2 3 4 5
| const router = new VueRouter({ mode: "history", base:"/app1/", routes })
|
刷新路由丢失
开发环境中,路由跳转后刷新页面可能会出现404错误。因为刷新页面时访问的资源找不到,因为vue-router
设置的路径不是真实存在的路径。vue.config.js
加入以下配置
1 2 3 4 5 6 7 8 9 10
| devServer: { open: false, historyApiFallback: { verbose: true, rewrites: [ { from: /^\/app1\/.*$/, to: "/app1.html" }, { from: /^\/app2\/.*$/, to: "/app2.html" }, ], }, }
|
既然本地开发的服务端要做配置,那么生产环境的nginx
服务器也需配置
1 2 3 4 5 6 7 8 9 10 11 12 13
| location / { try_files $uri $uri/ @router; index index.html; }
location @router { rewrite ^/app1/* /app1.html last; rewrite ^/app2/* /app2.html last; }
|
其他错误
Uncaught SyntaxError:Unexpected token
vue.config.js
配置
1 2 3
| module.exports = { publicPath: "/", }
|