单页面应用是如何实现URL变化不刷新页面
两种模式hash、history
Hash模式
-
原理:Hash模式基于URL的哈希(#)。它使用URL的hash(即
#后面的部分)来模拟一个完整的URL,从而实现页面的跳转。在Hash模式下,当URL的hash部分改变时,浏览器不会向服务器发送请求。 -
特点:
- 兼容性好,可以在所有浏览器中运行,包括不支持HTML5 History API的旧浏览器。
- 改变hash不会导致浏览器向服务器发送请求。
- 适用于那些不需要服务器渲染,或者不太关心URL美观的应用。
-
示例URL:
http://example.com/#/page1
History模式
-
原理:History模式利用HTML5的History API(特别是
pushState和replaceState方法)来维护浏览器历史记录。 -
特点:
- 提供了更“干净”的URL,没有哈希部分。
- 允许你在做路由跳转时,不向服务器发送请求。
- 对服务器有一定要求:所有的路由请求都应该定向到同一个html文件。如果服务器没有正确配置,直接访问或刷新非首页路由可能会导致404错误。
-
示例URL:
http://example.com/page1
如何监听两者URL的变化
监听hash变化
window.addEventListener('hashchange', function() {
console.log('Hash changed to: ' + window.location.hash); // 这里可以添加你的逻辑来响应 hash变化
});
window.location.hash = 'test'//改变URL的hash
监听history变化
1.当用户点击浏览器的前进或后退按钮时或者通过go、back函数调用,可以通过 window.onpopstate 事件监听器来响应历史记录的变化
window.onpopstate = function(event) {
console.log("location: " + document.location + ", state: " + JSON.stringify(event.state)); // 这里可以添加你的逻辑来响应历史记录的变化
};
注意事项:
history.go(0)或location.reload()用于刷新当前页面,但它们不会触发onpopstate事件。
2.history.pushState() 和 history.replaceState() 不会触发页面的重新加载也不会触发onpopstate 事件
//对pushState和replaceState进行重写
const originalPushState = history.pushState;
const originalReplaceState = history.replaceState;
// 重写 pushState 方法
history.pushState = function(state, title, url) {
// 调用原始 pushState 方法
originalPushState.apply(this, arguments);
// 触发自定义事件
window.dispatchEvent(new Event('statechange'));
};
// 重写 replaceState 方法
history.replaceState = function(state, title, url) {
// 调用原始 replaceState 方法
originalReplaceState.apply(this, arguments);
// 触发自定义事件
window.dispatchEvent(new Event('statechange'));
};
// 监听 statechange 事件
window.addEventListener('statechange', function() {
console.log('URL changed:', location.href);
});
window.history.pushState({a:1},'测试','/a')//触发statechange事件
前进(forward)和后退(back)功能
| 功能 | 描述 | JavaScript 方法 | 备注 |
|---|---|---|---|
| 后退 | 返回到浏览器历史记录中的上一个页面。 | history.back() 或 history.go(-1) | 如果历史记录中没有上一个页面,这些方法不会有任何效果。 |
| 前进 | 前往浏览器历史记录中的下一个页面。 | history.forward() 或 history.go(1) | 如果历史记录中没有下一个页面,这些方法不会有任何效果。 |
| 跳转 | 跳转到浏览器历史记录中的特定页面。 | history.go(n) | n 是一个整数,表示要前进或后退的页面数。n 可以是正数(前进),负数(后退),或 0(刷新当前页面)。 |
| 添加历史记录 | 在浏览器历史记录中添加一个新的记录。 | history.pushState(state, title, url) | state 是与新历史记录相关联的状态对象;title 目前大多数浏览器忽略这个参数;url 是新历史记录的URL。 |
| 替换历史记录 | 替换当前的历史记录项。 | history.replaceState(state, title, url) | 与 pushState 类似,但不添加新记录,而是替换当前记录。 |