vue-router
3 种模式
hash
: 使用URL hash
值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器。history
: 依赖HTML5 History API
和服务器配置。abstract
: 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式。
依赖的浏览器 API
- URL hash
js
window.onhashchange = function (e) {
console.log(e.oldURL); // 输出 https://www.baidu.com/
console.log(e.newURL); // 输出 https://www.baidu.com/#hash
};
window.location = "#hash"; // 或者 location.hash = "#hash"
window.onhashchange = function (e) {
console.log(e.oldURL); // 输出 https://www.baidu.com/
console.log(e.newURL); // 输出 https://www.baidu.com/#hash
};
window.location = "#hash"; // 或者 location.hash = "#hash"
HTML5 History API
state
: 查看 pushState() or replaceState() 修改后的 state 值,否则返回 null,不必等待 popstate 事件发生后再查看。length
:只读属性,返回当前 session 中的 history 个数,包含当前页面在内。举个例子,对于新开一个 tab 加载的页面当前属性返回值 1。back
: 在会话历史记录中向后移动一页。如果没有上一页,则此方法调用不执行任何操作。go
: 从会话历史记录中加载特定页面。你可以使用它在历史记录中前后移动,具体取决于 delta 参数的值。不传或者传零重新加载页面。forward
: 在会话历史中向前移动一页。等同于history.go(1)
pushState
: 向当前浏览器会话的历史堆栈中添加一个状态(state)。replaceState
: 修改当前历史记录实体,如果你想更新当前的 state 对象或者当前历史实体的 URL 来响应用户的的动作的话这个方法将会非常有用。onpopstate
: 当活动历史记录条目更改时,将触发popstate
事件。
需要注意的是调用
history.pushState()
或history.replaceState()
不会触发popstate
事件。只有在做出浏览器动作时,才会触发该事件,如用户点击浏览器的回退按钮(或者在 Javascript 代码中调用history.back()
或者history.forward()
方法) 。不同的浏览器在加载页面时处理popstate
事件的形式存在差异。页面加载时 Chrome 和 Safari 通常会触发popstate
事件,但 Firefox 则不会。
js
// 新开页面
location.href; // https://www.baidu.com/
window.addEventListener("popstate", (e) => {
console.log("popstate: ", JSON.stringify(event.state)); // 当前记录的 state
});
window.history.length; // 1
window.history.state; // null
window.history.go(); // 刷新页面
window.history.go(0); // 刷新页面
window.location = "#hash"; // https://www.baidu.com/#hash
window.history.length; // 2
window.history.back(); // 向前移动一页 https://www.baidu.com/
window.history.forward(); // 向前移动一页 https://www.baidu.com/#hash
window.history.go(-1); // 向后移动一页 https://www.baidu.com/
window.history.go(1); // 向前移动一页 https://www.baidu.com/#hash
// 状态对象是一个JavaScript对象,它与传递给 replaceState 方法的历史记录实体相关联.
var state = { page_id: 1, user_id: 5 };
// 大部分浏览器忽略这个参数
var title = ""; // 大部分浏览器忽略这个参数
// 可选;历史记录实体的URL. 新的URL跟当前的URL必须是同源; 否则 replaceState 抛出一个异常.
var url = "hello-world.html";
history.pushState(state, title, url); // https://www.baidu.com/hello-world.html
window.history.state; // {page_id: 1, user_id: 5}
window.history.length; // 3
var state = { page_id: 2, user_id: 6 };
var title = "";
var url = "hello-history.html";
history.replaceState(state, title, url); // https://www.baidu.com/hello-history.html
window.history.state; // {page_id: 2, user_id: 6}
window.history.length; // 3
// 新开页面
location.href; // https://www.baidu.com/
window.addEventListener("popstate", (e) => {
console.log("popstate: ", JSON.stringify(event.state)); // 当前记录的 state
});
window.history.length; // 1
window.history.state; // null
window.history.go(); // 刷新页面
window.history.go(0); // 刷新页面
window.location = "#hash"; // https://www.baidu.com/#hash
window.history.length; // 2
window.history.back(); // 向前移动一页 https://www.baidu.com/
window.history.forward(); // 向前移动一页 https://www.baidu.com/#hash
window.history.go(-1); // 向后移动一页 https://www.baidu.com/
window.history.go(1); // 向前移动一页 https://www.baidu.com/#hash
// 状态对象是一个JavaScript对象,它与传递给 replaceState 方法的历史记录实体相关联.
var state = { page_id: 1, user_id: 5 };
// 大部分浏览器忽略这个参数
var title = ""; // 大部分浏览器忽略这个参数
// 可选;历史记录实体的URL. 新的URL跟当前的URL必须是同源; 否则 replaceState 抛出一个异常.
var url = "hello-world.html";
history.pushState(state, title, url); // https://www.baidu.com/hello-world.html
window.history.state; // {page_id: 1, user_id: 5}
window.history.length; // 3
var state = { page_id: 2, user_id: 6 };
var title = "";
var url = "hello-history.html";
history.replaceState(state, title, url); // https://www.baidu.com/hello-history.html
window.history.state; // {page_id: 2, user_id: 6}
window.history.length; // 3
history 路由 404
问题场景:
- 非入口根路由页面刷新页面 404
- 非入口根路由页面新开页面 404
具体原因:
Vue 是属于单页应用,不管我们有多少页面,都只会有一个入口 index.html
。当遇到上面两种场景时,请求会发送到后端服务器,服务器找不到非入口根路由页面
只能返回 404。
- 解决方案:
使用 hash 模式路由或者后端做支持配置
bash
# nginx 配置
server {
listen 80;
server_name www.xxx.com;
location / {
index /data/dist/index.html;
try_files $uri $uri/ /index.html;
}
}
# 配置更新命令 nginx -s reload
# nginx 配置
server {
listen 80;
server_name www.xxx.com;
location / {
index /data/dist/index.html;
try_files $uri $uri/ /index.html;
}
}
# 配置更新命令 nginx -s reload
这么做以后,你的服务器就不再返回 404 错误页面,因为对于所有路径都会返回 index.html 文件;现在你可以在 Vue 应用里面覆盖所有的路由情况,然后在给出一个 404 页面
js
const router = new VueRouter({
mode: "history",
routes: [{ path: "*", component: NotFoundComponent }],
});
const router = new VueRouter({
mode: "history",
routes: [{ path: "*", component: NotFoundComponent }],
});