最近在学习vue-router源码,看的有点懵。
刚刚看了一篇文章觉得很不错,看完后没有那么懵了,决定自己理解后记录一下。
带着问题去思考
- 1.为什么会有前端路由?
- 2.前端路由解决了什么?
- 3.前端路由如何实现?
1
在现代框架(Vue-React)等出现前,几乎都是纯dom页面(传统页面),因前端越来越复杂,工程化等,现在大多项目都是单页面应用,单不一样的是,单页面引用就一个app.js,通过JS去渲染,那么如果有几十个页面如何展示呢?
2
此时就出现了前端路由,根据不同地址(pathname)展示不同组件,例如Vue-router和routeView,routeView就是一个占位,通过地址的不同塞入不同的组件。
3
一般使用俩种模式,hash和history模式。
-
hash模式
通过hashChange方法监听可以通过点击a标签改变#/后的url
可以通过修改window.location改变url
可以通过浏览器前进以上三种方法都可以被监听到
<body>
<ul>
<li>
<a href="#/page1">page1</a>
</li>
<li>
<a href="#/page2">page2</a>
</li>
</ul>
<div id="routeView"></div>
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', load)
window.addEventListener('hashchange', hashChange)
let routeView = null
function load() {
routeView = document.getElementById('routeView')
hashChange()
}
function hashChange() {
console.log(location.hash);
switch (location.hash) {
case '#/page1':
routeView.innerHTML = 'page1'
break;
case '#/page2':
routeView.innerHTML = 'page2'
break;
default:
routeView.innerHTML = 'page'
break;
}
}
</script>
</body>
- history模式
通过popstate事件实现,不过这个比较麻烦些。
这里需要解决a标签无法被监听的问题,注意思路就是禁用默认事件,然后添加点击回调获取href值然后调用popstate。
循环所有a标签,禁止默认事件
e.preventDefault()
<body>
<ul>
<li>
<a href="/page1">page1</a>
</li>
<li>
<a href="/page2">page2</a>
</li>
</ul>
<div id="routeView"></div>
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', Load)
window.addEventListener('popstate', PopChange)
var routeView = null
function Load() {
routeView = document.getElementById('routeView')
PopChange()
let aList = document.querySelectorAll('a[href]')
console.log(aList);
// 遍历 a 标签节点数组,阻止默认事件,添加点击事件回调函数
aList.forEach(aNode => aNode.addEventListener('click', function (e) {
e.preventDefault() //阻止a标签的默认事件
let href = aNode.getAttribute('href')
console.log(href);
// 手动修改浏览器的地址栏
// state, title, url
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
}
}
// window.addEventListener('DOMContentLoaded', load)
// window.addEventListener('hashchange', hashChange)
// let routeView = null
// function load() {
// routeView = document.getElementById('routeView')
// hashChange()
// }
// function hashChange() {
// console.log(location.hash);
// switch (location.hash) {
// case '#/page1':
// routeView.innerHTML = 'page1'
// break;
// case '#/page2':
// routeView.innerHTML = 'page2'
// break;
// default:
// routeView.innerHTML = 'page'
// break;
// }
// }
</script>
</body>