监听url的变化
在单页面应用(spa)中路由一般分为两类,hash 和 history; 两者的实现方式有所不同,但核心相同都是为了更新视图而不重新请求页面。
hash
在 window.location 的 hash 值中 包含当前页面 url 中 ‘#’以及后面的 url 片段。并且哈希值它不会作为路径的一部分随着 http 请求,发给服务器。 当改变 location.hash 时会触发 onhashchange 事件。
hash 路由就是通过监听 onhashchange 的变化从而能根据不同的 hash 值渲染不同的页面,借此实现无刷新跳转的功能。
/**
* www.lpxblog.cn/#/home
*/
console.log(location.hash); // '#/home'
// 监听 hashchange事件
window.addEventListener("hashchange", function (event) {
// doSomething
});history
window.history 中提供了一系列方法改变页面 url,其中 pushState 和 replaceState 都会改变当前页面显示的 url,不刷新页面。
两者区别在于:
- pushState 可以将给定的数据压入到浏览器会话历史栈中,使 History.length 加 1
- replaceState 将当前的会话页面的 url 替换成指定的数据。不会增加 History.length
跟 hash 改变出发 hashchange 事件不同,pushState 和 replaceState 调用不会触发事件。
可以通过改写方法触发 popState 事件,或者通过自定义事件的方式进行 PS:自定义事件传参可以使用 CustomEvent 或直接挂在 event 实例上
const rewite = function (type) {
const orig = history[type];
const evt = new Event(type);
return function () {
const rval = orig.apply(this, arguments);
evt.arguments = arguments; // 也可以换成CustomEvent 不过要把 new CustomEvent(type, {detail:arguments}) 放在这里
window.dispatchEvent(evt);
return rval;
};
};
history.pushState = rewite("pushState");
history.replaceStat = rewite("replaceStat");
// 监听自定义事件
window.addEventListener("pushState", function (e) {
//dosomething
// e.arguments 即rewite事件中记录的arguments
});
// 触发
window.history.pushState(null, "", "one");history 路由 要解决的问题
history 模式的时候路径会随着 http 请求发送给服务器,项目打包部署时,需要后端配置 nginx,当应用通过 pushState 跳转到某个页面后,因为此时是前端路由控制页面跳转,虽然 url 改变,但是页面只是内容改变,并没有重新请求,所以这套流程没有任何问题。但是,如果在当前的页面刷新一下,此时会重新发起请求,如果 nginx 没有匹配到当前 url,就会出现 404 的页面。
而 hash 虽然可以改变 URL,但不会被包括在 HTTP 请求中。它被用来指导浏览器动作,并不影响服务器端,因此,改变 hash 并没有改变 URL,所以页面路径还是之前的路径,nginx 不会拦截。