【React】react-router-dom中的HashRouter和BrowserRouter实现原理
2024-01-07 17:35:17
1. 前言
? ? ? ? 在之前整理BOM的五个对象时,提到:
- location.hash发生改变后,会触发hashchange事件,且history栈中会增加一条记录,但页面不会重新加载——实现HashRouter的关键
- history.pushState(state, '', URL)执行后,history栈中会增加一条记录,但页面不会重新加载,回退(history.back()或history.go(-1))会触发popstate事件,location.pathname发生改变——实现BrowserRouter的关键
? ? ? ? 本篇通过举例方式详细描述实现的过程。
2. HashRouter的原理
2.1 原理要点
- 通过<a>元素href属性修改URL的hash值(或location.hash='#/xxx'修改,或前进后退修改);
- location.hash发生改变,页面不会重新加载;
- location.hash发生改变,URL也会改变(hash是URL的一部分),新URL被推入history栈中;
- location.hash发生改变,会触发window的hashchange事件;
- 通过给window.onhashchange绑定事件处理函数,监听hash变化,根据hash值选择渲染的组件。
注:根据hash值变化渲染组件,不会影响hash原有作为锚点的功能(锚点功能:根据#后面字符串滚动到对应id的元素 )
2.2 示例源码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hash Router</title>
</head>
<body>
<a href="#/user">Go user</a>
<a href="#/info">Go info</a>
<div id="root"></div>
<!-- <div style="height: 600px;"></div>
<div id="/info"></div> -->
<script>
let root = document.getElementById('root');
window.onhashchange = function(event) {
if(window.location.hash === '#/user') {
root.innerHTML = `
<label>
用户名:
<input value="小明" placeholder="user name"/>
</label>
`;
} else {
root.innerHTML = `
<label>
年龄:13岁
</label>
`;
}
}
</script>
</body>
</html>
3. BrowserRouter的原理
3.1 原理要点
- window不支持onpushstate事件,需要为window构造onpushstate事件,并绑定事件处理函数,重写history.pushState,保证执行history.pushState就会触发onpushstate事件;
- 可以为菜单项绑定click事件处理函数,执行重写的history.pushState(state,title,url)修改URL;
- 执行重写的history.pushState,页面不会重新加载,但location.pathname发生改变,并触发window的onpushstate事件;
- 通过window.onpushstate的事件处理函数,监听pathname变化,根据pathname值选择渲染的组件;
- 前进和后退会改变URL,页面不会重新加载,location.pathname发生改变,并触发window的onpopstate事件;
- 通过window.onpopstate绑定的事件处理函数,监听pathname变化,根据pathname值选择渲染的组件。
3.2 示例源码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hash Router</title>
</head>
<body>
<div id="root"></div>
<script>
let root = document.getElementById('root');
window.onpushstate = function(state, title, url) {
console.dir({
type: 'onpushstate',
state,
pathname: url
});
render(url);
}
// 修改history.pushState方法,将window.onpushstate事件绑入
bindPushstate(window.history);
function bindPushstate(history) {
let pushState = history.pushState;
history.pushState = function(state, title, url) {
if(typeof window.onpushstate === 'function') {
window.onpushstate(state, title, url);
}
return pushState.apply(history, arguments);
}
}
window.onpopstate = function(event) {
const pathname = window.location.pathname;
console.dir({
type: event.type,
state: event.state,
pathname
});
render(pathname);
}
function render(pathname) {
if(pathname === '/user') {
root.innerHTML = `
<label>
用户名:
<input value="小明" placeholder="user name"/>
</label>
`;
} else if(pathname === '/info') {
root.innerHTML = `
<label>
年龄:13岁
</label>
`;
} else {
root.innerHTML = `
<label>
需要填写个人信息
</label>
`;
}
}
setTimeout(() => {
window.history.pushState({ page: 1 }, 'user', '/user');
}, 2000);
setTimeout(() => {
window.history.pushState({ page: 2 }, 'info', '/info');
}, 4000);
setTimeout(() => {
window.history.pushState({ page: 3 }, 'help', '/help');
}, 6000);
</script>
</body>
</html>
4. 总结
????????再牛的建筑都离不开一块一块砖瓦,学到很多高大上的框架和上层API时,再回过头来看基础,会更加深对框架和上层API的理解。
注:以上,如有不合理之处,还请帮忙指出,大家一起交流学习~??
文章来源:https://blog.csdn.net/weixin_45620943/article/details/135401455
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!