单页面应用对路由如何处理

179 阅读3分钟

单页面应用是如何实现URL变化不刷新页面

两种模式hash、history

Hash模式

  1. 原理:Hash模式基于URL的哈希(#)。它使用URL的hash(即#后面的部分)来模拟一个完整的URL,从而实现页面的跳转。在Hash模式下,当URL的hash部分改变时,浏览器不会向服务器发送请求。

  2. 特点

    • 兼容性好,可以在所有浏览器中运行,包括不支持HTML5 History API的旧浏览器。
    • 改变hash不会导致浏览器向服务器发送请求。
    • 适用于那些不需要服务器渲染,或者不太关心URL美观的应用。
  3. 示例URLhttp://example.com/#/page1

History模式

  1. 原理:History模式利用HTML5的History API(特别是pushStatereplaceState方法)来维护浏览器历史记录。

  2. 特点

    • 提供了更“干净”的URL,没有哈希部分。
    • 允许你在做路由跳转时,不向服务器发送请求。
    • 对服务器有一定要求:所有的路由请求都应该定向到同一个html文件。如果服务器没有正确配置,直接访问或刷新非首页路由可能会导致404错误。
  3. 示例URLhttp://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)); // 这里可以添加你的逻辑来响应历史记录的变化
};

注意事项:

  1. 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 类似,但不添加新记录,而是替换当前记录。