Router
是路由管理工具,Vue
,React
中分别常用的是 vue-router
和 react-router-dom
。
在探究其实现原理前,我们先来复习一下 Location
对象
Location
对象中包含有关当前 URL
的信息。
而当浏览器 URL
发生改变后 PopStateEvent
事件。
window.addEventListener('popstate', e => {
console.log(e);
});
在 vue-router
和 react-router-dom
分别 Hash
模式和 History
模式
-
Hash
路由带有#
号,比如现在网易云音乐就是采用的Hash
模式。(不美观) -
History
变化页面会刷新,Hash
变化页面不会刷新 -
设置
Hash
需要在服务端设置静态资源index.html
,History
不需要设置
Hash 模式的实现
思路:我们需要监听 Hash
的变化,从而渲染不同的页面
浏览器为我们提供了 Hash
变化的 HashChangeEvent
的事件,我们可以直接监听
window.addEventListener('hashchange', e => {
console.log('hash change', e);
});
<a href="#/index">index</a>
<a href="#/home">home</a>
监听到了 Hash
的变化,那么我们在来根据 Hash
来获取当前 Hash
需要展示的内容给渲染出来
window.addEventListener('hashchange', e => {
console.log('hash change', e);
renderDOM(location.hash);
});
function renderDOM(path) {
let _path = path.replace(/^#\//gi, '');
let app = document.getElementById('app');
app.innerHTML = '';
let ele = document.createElement('div');
ele.innerHTML = `<h1>${_path}</h1>`;
app.appendChild(ele);
}
History 模式的实现
思路:我们需要监听 History
的变化,并且阻止页面的跳转,从而渲染不同的页面
在复习 Location
的时候我们提到了 PopStateEvent
事件,当页面发生改变的时候会被触发。
let els = document.getElementsByTagName('a');
for (let el of els) {
el.addEventListener('click', e => {
// 阻止默认行为
e.preventDefault();
// 获取即将跳转的页面
let path = el.getAttribute('href');
renderDOM(path);
});
}
function renderDOM(path) {
let _path = path.replace(/\//gi, '');
let app = document.getElementById('app');
app.innerHTML = '';
let ele = document.createElement('div');
ele.innerHTML = `<h1>${_path}</h1>`;
app.appendChild(ele);
}
此时我们页面的视图发生了改变,但是页面的路由没有变化,应为我们为了不让页面跳转,阻止了 a 标签的默认行为,所以无法跳转
而 History
对象为我们提供了 pushState
的 API
改变路由,我们在每次路由切换的时候调用即可实现路由的变化
history.pushState({}, '', path);
拓展
当我们刷新浏览器时,页面会 404
,这个行为让我们联想到一个 History
模式下 SPA
应用程序刷新会404
,原因就在于当前资源在静态文件中不存在,所以我们需要配置一个 默认静态资源 index.html