路由的概念来源于服务端,在服务端中路由描述的是 URL与处理函数之间的映射关系,当然也会处理不同的URL来展示不同
的视图界面。
随着Ajax的盛行,无刷新交互成为了当下的主流,我们更希望在无刷新的情况下完成不同URL来展示不同的视图界面,即在一
个页面中完成路由的切换(俗称:单页面应用开发SPA),这就是前端路由。
那么如何做到在一个页面中完成URL与UI的映射关系呢?一般我们有两种实现方案:
- hash模式
- history模式
hash模式
hash模式
hash是 URL中 hash (#) 及后面的那部分,常用作锚点在页面内进行导航,改变 URL中的 hash部分不会引起页面刷新。我们通
过 hashchange 事件来监听 hash值的改变,这样就可以显示不同的UI内容,示例代码如下:
<body>
<ul>
<!-- 定义路由 -->
<li><a href="#/home">home</a></li>
<li><a href="#/about">about</a></li>
<!-- 渲染路由对应的 UI -->
<div id="routerView"></div>
</ul>
</body>
<script>
window.addEventListener('hashchange', onHashChange)
onHashChange()
function onHashChange () {
switch (location.hash) {
case '#/home':
routerView.innerHTML = 'Home'
break;
case '#/about':
routerView.innerHTML = 'About'
break;
}
}
</script>
history模式
history对象提供了pushState方法和popstate事件,pushState方法可以让URL发生改变但并不会引起页面的刷新,而popstate事件则
用来监听URL改变的值,这样就可以显示不同的UI内容,示例代码如下:
<body>
<ul>
<!-- 定义路由 -->
<li><a href="/home">home</a></li>
<li><a href="/about">about</a></li>
<!-- 渲染路由对应的 UI -->
<div id="routerView"></div>
</ul>
</body>
<script>
let linkList = document.querySelectorAll('a[href]')
for(let i=0;i<linkList.length;i++){
linkList[i].addEventListener('click', function(e){
e.preventDefault()
history.pushState(null, '', this.getAttribute('href'))
onPopState()
})
}
window.addEventListener('popstate', onPopState)
onPopState()
function onPopState () {
switch (location.pathname) {
case '/home':
routerView.innerHTML = 'Home'
break;
case '/about':
routerView.innerHTML = 'About'
break;
}
}
</script>
注意:以上代码要在服务器环境下运行,才会生效。
这种history模式存在一个问题,那就是当刷新页面的时候就会出现找不到页面的情况,即:Cannot GET /home。这主要是因为
history模式的URL地址跟普通的URL地址没有任何区别,刷新的时候服务器会去找相关的资源,我们在服务器上根本就没有这
个资源,就会出现找不到的现象。
解决这个问题,你需要做的就是在你的服务器上添加一个简单的回退路由。如果 URL不匹配任何静态资源,它应提供与你的
应用程序中的 index.html 相同的页面。漂亮依旧!
下面是nginx服务器实现的示例:
location / {
try_files $uri $uri/ /index.html;
}
Vue框架给我们提供了一个第三方的路由框架,即:vue-router,官网地址:https://router.vuejs.org/zh/index.html。vue-router提
供了两种路由模式,可自由选择,而且在开发阶段,脚手架还帮我们处理了history找不到页面的情况。