因为 AJAX 的出现诞生了单页应用这种网页类型,单页应用简单的说就是前端通过 AJAX 加载和动态改变 DOM 内容来切换页面,网页本身并不会刷新和跳转。像 YouTube 、Google Play 、网易云音乐 等 都属于单页应用。虽然页面不会跳转但观察浏览器地址栏就会发现地址是会改变的,手动刷新网页也不会转到首页,这就是前端实现的路由。
目前常见的实现路由的方式有两种,一种是通过 hash 来实现,另一种是通过 HTML5 中加入的 history API 来实现。
hash
这里主要是实现改变 URL,AJAX 的部分就不写了,下面是一个简单的 HTML:
HTML
<div>无内容</div>
<ul>
<li><a href="#red">红色</a></li>
<li><a href="#green">绿色</a></li>
<li><a href="#blue">蓝色</a></li>
</ul>
只需要在链接 URL 前面加一个 # 链接就不会跳转。这里要实现的功能就是点击链接后 URL 改变,div 中的内容也改变,刷新网页 div 中的内容也不会消失,下面是 JS 代码:
JavaScript
// 封装一个函数,根据传入的 hash 改变 div 的内容
let setPage = hash => {
// 如果 hash 没有内容
if (hash == '' || hash == null) {
hash = 'white';
}else {
hash = hash.replace('#', ''); // 去除 #
}
// div 的内容
let content = {
red: "红色",
green: "绿色",
blue: "蓝色",
white: "无内容"
};
// 根据传入的 hash 改变 div 的内容
document.querySelector('div').innerHTML = content[hash];
// 根据传入的 hash 改变 div 的背景颜色
document.querySelector('div').style.background = hash;
// 根据传入的 hash 设置页面标题
document.title = content[hash];
};
// 给 window 添加一个 hashchange 事件,当 hash 改变就会触发 hashchange 事件
window.addEventListener('hashchange', (event) => {
setPage(location.hash); // 根据获取的 hash 改变 div 的内容
});
// 执行 setPage 函数,刷新页面 div 的效果也不会消失
setPage(location.hash);
因为注释比较多 看上去可能比较长,实际很简单,下面是详细说明:
location.hash 属性
如果 URL 中包含 # 通过 location.hash 可获取 # 和后面的内容。location.hash 是一个可读可写的属性,直接修改 location.hash 的内容 URL 也会改变。
hashchange 事件
当窗口 URL # 后面的内容改变时就会触发 hashchange 事件,hashchange 还包含两个属性:
event.newURL
当前页面的完整 URL。
event.oldURL
前一个 URL,也就是更改之前的 URL。
setPage 函数封装了 改变 div 的内容和背景颜色、改变页面标题,当 hashchange 监听到 URL 变化时就会调用 setPage 函数,刷新或打开页面也会调用 setPage 函数。使用 hash 路由最合兴的就是 location.hash 属性 和 hashchange 方法,hashchange 方法需要绑定到 window 。
下面是实现效果:

在历史记录中也能看到:

注意!如果链接 URL # 后面的内容和页面元素的 id 相同 在点击链接时会跳转到相同 id 元素的区域。
history
history 是 HTML5 中加入的 API,主要功能就是操作浏览器的会话历史记录,下面是 HTML:
HTML
<div>无内容</div>
<ul>
<li><a href="red">红色</a></li>
<li><a href="green">绿色</a></li>
<li><a href="blue">蓝色</a></li>
</ul>
这里要实现的功能还是点击链接改变 URL 和 div 的效果,同时添加历史记录,下面是 JS:
JavaScript
let link = document.querySelectorAll("li a"); // 获取链接
// 封装一个函数,根据传入的 data 改变 div 的内容
let setPage = data => {
// div 的内容
let content = {
red: "红色",
green: "绿色",
blue: "蓝色",
white: "无内容"
};
// 根据传入的 data 改变 div 的内容
document.querySelector('div').innerHTML = content[data];
// 根据传入的 data 改变 div 的背景颜色
document.querySelector('div').style.background = data;
// 根据传入的 data 设置页面标题
document.title = content[data];
};
for (let i = 0; i < link.length; i++) {
// 链接点击
link[i].addEventListener("click", event => {
event.preventDefault(); // 阻止浏览器跳转
let el = event.target; // 获取当前点击的链接
// 修改 URL 和历史记录
history.pushState(el.getAttribute('href'), '', el.href);
// 根据点击链接的 href 来设置 div 的效果
setPage(el.getAttribute('href'));
});
}
// 给 window 添加 popstate 事件,点击浏览器的前进和后退就会触发 popstate
window.addEventListener('popstate', event => {
let data = event.state; // history.pushState 传入的数据
// 如果没有数据
if (data == undefined) {
data = 'white';
}
// 根据 history.pushState 传入的数据来设置 div 的效果
setPage(data);
});
这里也是因为注释比较多,实际很简单,下面是详细说明:
history.pushState(data, title, url) 方法
在不跳转的情况下改变 URL,同时添加到历史记录,下面是参数说明:
| 参数 | 类型 | 说明 | |-------|--------|---------------------------| | data | state | 一个状态对象,可以通过 popstate 事件读取 | | title | string | 标题,对大多数浏览器都无效。 | | url | string | 要添加到历史记录的 URL |
history.replaceState(data, title, url) 方法
在不跳转的情况下改变 URL,同时替换历史记录,和 history.pushState 不一样的地方就是 history.replaceState 只会替换历史记录,不会添加历史记录,也就是说无论执行多少次都只会有一条记录,参数可以参考 history.pushState 的参数。此方法在这里暂时没有用到。
popstate 事件
当浏览器前进或者后退时就会触发 popstate 事件,注意!只有在同一个文档前进或者后退才会触发 popstate 事件,不同文档之间跳转并不会触发 popstate 。popstate 也包含一些属性:
event.state
获取 history.replaceState 或 history.pushState 设置的状态对象。
history.back() 方法
移动到上一条历史记录,类似于浏览器的后退按钮。这里暂时没有用到此方法。
history.forward() 方法
移动到下一条历史记录,类似于浏览器的前进。这里暂时没有用到此方法。
history.go() 方法
接收一个数值,以当前 URL 为基准移动到指定的 URL,例如 history.go(-1) 就是后退一次,history.go(1) 就是前进一次,history.go(0) 就是直接刷新当前页面。此处暂时没有用到此方法。
history.back()、history.forward()、history.go() 都能触发 popstate 事件。
setPage 函数封装了更改 div 的标题、背景颜色,更改页面标题。因为 history.pushState 不会触发 popstate 事件,所以在点击按钮时还需要调用 setPage 函数来设置 div 的效果。
注意!直接使用 .href 和 getAttribute('href') 获取的属性是不一样的,.href 获取的是完整的 URL,getAttribute('href') 只能获取 href 中的内容。
history 路由最合兴的就是 history.pushState 方法 和 popstate 事件,popstate 事件需要绑定到 window 。
下面是 history 路由的效果:

注意!如果使用 history 路由 服务器需要设置 404 重定向,把 404 重定向到首页,否则刷新网页或访问历史记录会出现 404 。
版权声明:本文为原创文章,版权归 Mr. Ma's Blog 所有,转载请联系博主获得授权。
本文地址:https://www.misterma.com/archives/788/
如果对本文有什么问题或疑问都可以在评论区留言,我看到后会尽量解答。
51工具盒子