1、前端路由3问?
- 为什么会出现前端路由
- 前端路由解决了什么问题
- 前端路由实现的原理
2、传统页面
整个项目都是DOM直出,返回的HTML就是最终的效果
3、单页面
react Vue 单页面应用框架通用特点,通过【js渲染页面】
单页面中10几个页面是如何互相跳转的,这个时候前端路由就出现了,根据浏览器pathname匹配不同组件,更新DOM
4、hash哈希路由
#后面的发生变化可以被浏览器的hashchange监听到,而且不会重新向浏览器发送请求,浏览器路由会
hashchange可以监听到如下时间
- a标签改变浏览器
- 浏览器的前进后退
- window.location方法,改变浏览器地址
window.addEventListener('DOMContentLoaded', Load)
window.addEventListener('hashchange', HashChange)
// 展示页面组件的节点
var routeView = null
function Load() {
routeView = document.getElementById('route-view')
HashChange()
}
function HashChange() {
// 每次触发 hashchange 事件,通过 location.hash 拿到当前浏览器地址的 hash 值
// 根据不同的路径展示不同的内容
switch(location.hash) {
case '#/page1':
routeView.innerHTML = 'page1'
return
case '#/page2':
routeView.innerHTML = 'page2'
return
default:
routeView.innerHTML = 'page1'
return
}
}
5、history历史模式
history 模式会比 hash 模式稍麻烦一些,因为 history模式依赖的是原生事件 popstate
history监听 url 中的路径变化,需要客户端和服务端共同的支持;
history常用方法
- history.back ()
- history.forward()
- history.go(number)
- history.pushState(obj, title, url)
- history.replaceState(obj, title, url)
这5中方法都可以修改修改页面URL而不发送请求,但是页面重新刷新会报错,因为重新刷新会想浏览器发送HTTP请求,所以用history还得服务器配合
注意事项,popstate无法监听到
- history.pushState()
- history.replaceState不会触发popstate
- a标签标签(a标签只改变pathname不会改变hash)
解决a标签无法被popstate监听到
遍历页面上的所有 a 标签,阻止 a 标签的默认事件的同时,加上点击事件的回调函数,在回调函数内获取 a 标签的 href 属性值,再通过 pushState 去改变浏览器的 location.pathname 属性值。然后手动执行 popstate 事件的回调函数,去匹配相应的路由
<body>
<div>
<ul>
<li><a href="/page1">page1</a></li>
<li><a href="/page2">page2</a></li>
</ul>
<div id="route-view"></div>
</div>
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', Load)
window.addEventListener('popstate', PopChange)
var routeView = null
function Load() {
routeView = document.getElementById('route-view')
// 默认执行一次 popstate 的回调函数,匹配一次页面组件
PopChange()
// 获取所有带 href 属性的 a 标签节点
var aList = document.querySelectorAll('a[href]')
// 遍历 a 标签节点数组,阻止默认事件,添加点击事件回调函数
aList.forEach(aNode => aNode.addEventListener('click', function(e) {
e.preventDefault() //阻止a标签的默认事件
var href = aNode.getAttribute('href')
// 手动修改浏览器的地址栏
history.pushState(null, '', href)
// 通过 history.pushState 手动修改地址栏,
// popstate 是监听不到地址栏的变化,所以此处需要手动执行回调函数 PopChange
PopChange()
}))
}
function PopChange() {
console.log('location', location)
switch(location.pathname) {
case '/page1':
routeView.innerHTML = 'page1'
return
case '/page2':
routeView.innerHTML = 'page2'
return
default:
routeView.innerHTML = 'page1'
return
}
}
</script>
</body>
pushState replaceState无法被监听到解决办法
dispatchEvent
const listener = function (type) {
var orig = history[type];
return function () {
var rv = orig.apply(this, arguments);
var e = new Event(type);
e.arguments = arguments;
window.dispatchEvent(e);
return rv;
};
};
window.history.pushState = listener('pushState');
window.history.replaceState = listener('replaceState');
// 监听自定义事件
window.addEventListener('pushState', this.refresh, false);
window.addEventListener('replaceState', this.refresh, false);