前端路由
路由这个概念最先是后端出现的,简单来说就是用来跟后端服务器进行交互的一种方式,通过不同的路径,来请求不同的资源,请求不同的页面是路由的其中一种功能。
随着 ajax 的流行,异步数据请求交互运行在不刷新浏览器的情况下进行。而异步交互体验的更高级版本就是 SPA —— 单页应用。单页应用不仅仅是在页面交互是无刷新的,连页面跳转都是无刷新的,为了实现单页应用,所以就有了前端路由。
类似于服务端路由,前端路由实现起来其实也很简单,就是匹配不同的 url 路径,进行解析,然后动态的渲染出区域 html 内容。但是这样存在一个问题,就是 url 每次变化的时候,都会造成页面的刷新。那解决问题的思路便是在改变 url 的情况下,保证页面的不刷新。
hash 模式
在 2014 年之前,大家是通过 hash 来实现路由,url hash 就是类似于:
http://www.xxx.com/#/login
#后面 hash 值的变化,并不会导致浏览器向服务器发出请求,浏览器不发出请求,也就不会刷新页面。
另外每次 hash 值的变化,还会触发 hashchange 这个事件,通过这个事件我们就可以知道 hash 值发生了哪些变化。然后我们便可以监听 hashchange 来实现更新页面部分内容的操作。
function matchAndUpdate () {
// todo 匹配 hash 做 dom 更新操作
}
window.addEventListener('hashchange', matchAndUpdate)
hash 模式背后的原理是 onhashchange 事件,可以在 window 对象上监听这个事件:
window.onhashchange = function(event){
console.log(event.oldURL, event.newURL);
let hash = location.hash.slice(1);
document.body.style.color = hash;
}
HashHistory有两个方法:HashHistory.push()将新路由添加到浏览器访问历史的栈顶 和 HashHistory.replace()替换掉当前栈顶的路由。
因为hash发生变化的url都会被浏览器记录(历史访问栈)下来,从而你会发现浏览器的前进后退都可以用了。这样一来,尽管浏览器没有请求服务器,但是页面状态和url一一关联起来。
history 模式
14年后,因为HTML5标准发布。多了两个 API,pushState
和 replaceState
,通过这两个 API:
- 可以改变 url 地址且不会发送请求
- 不仅可以读取历史记录栈,还可以对浏览器历史记录栈进行修改
同时还有 popstate
事件:
- 当浏览器跳转到新的状态时,将触发
popState
事件
function matchAndUpdate () {
// todo 匹配路径 做 dom 更新操作
}
window.addEventListener('popstate', matchAndUpdate)
通过这些就能用另一种方式来实现前端路由了,但原理都是跟 hash 实现相同的。
如果要考虑url规范,就要使用history模式,例如在app中需要将页面分享到第三方app,有的app里面url是不允许带有#号的,所以要将#号去除那么就要使用history模式。
修改历史状态
包括了pushState
,replaceState
两个方法,这两个方法接收三个参数:stateObj
,title
,url
window.history.pushState(stateObject, title, URL)
window.history.replaceState(stateObject, title, URL)
切换历史状态
包括back
,forward
,go
三个方法,对应浏览器的前进forward,后退back,跳转go操作。
history.go(-2); // 后退两次
history.go(2); // 前进两次
history.back(); // 后退
hsitory.forward(); // 前进
history模式怕啥
不怕前进,不怕后退,就怕刷新。因为没有 # 号,所以当用户刷新页面之类的操作时,浏览器还是会给服务器发送请求。例如请求的路径是/user/id
,这部分是会传到服务器的,如果服务器中没有相应的响应或者资源,会分分钟刷出一个404来。
为了避免出现这种情况,所以这个实现需要服务器的支持,需要把所有路由都重定向到根页面。
const Koa = require('koa')
const Router = require('koa-router');
const static = require('koa-static')
const fs = require('fs');
const app = new Koa();
const router = new Router();
let str;
fs.readFile('../dist/index.html', "utf-8", (err, data) => {
if (err) {
ctx.body = "error found"
}
str = data.toString();
})
// 解决vue 路由在 history刷新 404情况
router.get('*', async(ctx, next) => {
if (ctx.url !== "/index.html") {
console.log("在这里返回")
ctx.body = str;
}
})
app.use(static("../dist/"));
app.use(router.routes()) //启动路由
app.use(router.allowedMethods());
app.listen(8989, () => {
console.log("监听服务器地址:127.0.0.1:8989");
})
参考:
前端路由简介以及vue-router实现原理
vue-router两种模式的区别
vue路由的两种模式,hash与history的区别