如何优雅的使用 Vue Router History 模式

如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。 —— Vue Router 官网

为啥要使用 History 模式

还能有什么原因,hash 模式的 # 不好看呗,当然了,我们也不能仅仅只看颜值,还有一些其他原因,例如 hash 模式下对一些需要锚点功能的需求会和他的路由机制有冲突,而相比于 hash 模式,hisitory 模式有以下几个点值得留意:

  1. 新的 URL 可以是与当前 URL 同源的任意 URL 。而设置 window.location 仅当你只修改了哈希值时才保持同一个 document。
  2. 设置的新 URL 可以与当前 URL 一模一样,这样也会把记录添加到栈中,而 hash 设置的新值必须与原来不一样才会触发动作将记录添加到栈中。
  3. 你可以为新的历史记录项关联任意数据。而基于哈希值的方式,则必须将所有相关数据编码到一个短字符串里。
  4. 可额外设置 title 属性供后续使用。

配置 History

说干就干,开始将我们项目的路由模式切换成 history 模式。

1
2
3
4
const router = new VueRouter({
mode: 'history',
routes: [...]
});

配置就是这么 easy,按道理,本篇文章到这也差不多可以结束了,但如果真的这么结束了,那我只能说 too young, too simple ,配置虽然简单,但切换后不仅需要后台的支持,还有一堆的坑等着你来踩呢。

后端配置

当我们在界面上点击刷新按钮的时候,会发现页面一片空白,这是为啥?打开控制台就会看到几个显眼的404,至于原因嘛,在官网上就有提到,History 这种模式要玩好,还需要后台配置支持。简单来讲就是,如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是我们 app 依赖的页面。
至于怎么配置,那就不是我们前端关心的事了,当然咯,作为励志成为爆栈工程师的我们,还是有必要了解一下这个配置过程,具体看官网就行,不行就 Google。

这里针对官网的内容补充一点就是,实际使用过程中,我们往往会将整个 dist 目录放到网站的根目录下,这时候就需要配置项目的 baseUrl。

  1. vue.config.js 中配置 publicPath
    1
    2
    3
    module.exports = {
    publicPath: '/dist'
    }
  2. 路由配置 base
    1
    2
    3
    4
    5
    const router = new VueRouter({
    mode: 'history',
    base: process.env.BASE_URL,
    routes: [...]
    });
  3. 修改 nginx 配置
    1
    2
    3
    location / {
    try_files $uri $uri/ /dist/index.html;
    }

此时我们的访问路径就应该类似这样:http://localhost:8888/dist/home

有时候,我们可能需要 URL 的前缀不是 dist 而是 vue,当然也有可能想通过一个二级域名或者不带前缀的域名来访问,对于这样的需求,这里仅提供一种 nginx 反向代理的方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
listen 8887;

location / {
rewrite / /vue ;
}

location /vue {
proxy_pass http://localhost:8888/dist;
proxy_set_header Host $host:$server_port;
}
}

server {
listen 8888;
server_name localhost;

location / {
root html;
index index.html index.htm;
try_files $uri $uri/ /dist/index.html;
}
}

踩坑实录

如果只是上面提到的简单配置就能搞定,那这篇文章也没啥好写的,毕竟官网写的那么详细,既然写了,就说明,本人在从 hash 模式切换到 history 模式的过程中,除了配置之外,还有那么一丢丢可以聊一聊的故事。

Uncaught SyntaxError: Unexpected token <

项目用的脚手架 vue-cli 3,之前 hash 模式打包后,会出现找不到静态资源的情况,将 publicPath 修改为 ‘./‘(默认是’/‘),很凑巧,改成 history 模式后,会报错 Uncaught SyntaxError: Unexpected token < ,该问题产生原因跟我们之前 hash 模式下打包时配置的相对路径有关,将其改回绝对路径即可。

本地预览打包后的项目

hash 模式下,我们直接打包后,打开 dist 目录下的 index.html 文件就可以预览,但是 history 模式不行,那咋整呢?自己本地搭一个服务器,运行静态资源呗。

既然是前端开发,最熟悉的莫过于 Node 了,这里以 express 为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
const express = require('express');
const app = express();

const PORT = 8081;

app.set('port', PORT);

app.use('/', express.static('./dist'));

app.listen(app.get('port'), () => {
console.log('Server Running');
});

启动服务器即可访问,既然是 history 模式,就不可避免的会存在我们前文提到的刷新后界面空白问题,所以我们还需要做一个重定向处理。

1
2
3
const history = require('connect-history-api-fallback');

app.use(history());

这样就完了吗?还不够!因为之前开发环境是通过配置 devServer.proxy 来请求后端接口,所以我们还需要加一个反向代理。

1
2
3
4
5
const HOST = 'http://xx.xxx.xx.xx:xx';

app.use(proxy('/xxx', {
target: HOST
}));

然后重启服务,预览效果,破菲特!

总结

啰嗦了这么多,其实总结起来就是一句话,看官方文档,官方文档不够就 Google 来凑!

查看评论