前端路由是指在浏览器端控制页面内容切换显示的机制。在没有服务器端参与的情况下,前端路由可以根据URL的变化,对应展现不同的内容,实现页面的“伪”跳转。
在学习路由之前首先要了解一下SPA单页面应用
SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载。
其实就是说,我们点击页面上的一些东西,并没有真正的发送请求进行页面跳转,而是在组件之间切换而已,仅仅刷新局部资源。
我们熟知的JS框架如react,vue,angular,ember都属于SPA
与之对应的是多页面应用,他们的区别如下
优点:
缺点
为了实现前端路由,SPA需要监听URL的变化,并据此渲染对应的组件或页面不同部分,无需重新加载整个页面。下面让我们分别深入了解两种路由模式的原理。
hash和history
hash模式原理:
window.location.hash
读写URL中的hash值,并且当hash值变化时,页面不会触发重新加载。hashchange
事件,在URL的hash部分变化时根据定义好的路由映射关系来动态渲染内容。location.hash
来实现的,location.hash
的值就是URL中#后面的内容 其实现原理就是监听#后面的内容来发起Ajax请求来进行局部更新,而不需要刷新整个页面。hashchange
事件来监听 URL 的变化,以下这几种情况改变 URL 都会触发 hashchange
事件:浏览器前进后退改变 URL、<a>
标签改变 URL、window.location改变URL。
// Hash模式的简易实现
window.addEventListener('hashchange', routeChange);
function routeChange() {
const hash = window.location.hash.slice(1); // Remove the '#' symbol
// 基于hash值显示不同内容
routerView.innerHTML = routes[hash] ? routes[hash] : routes['404'];
}
我使用了vue中的router.push,发现没有触发hashchange事件, 这是因为hashchange是浏览器的事件,push是vue内部的机制在处理路由变化。
History模式原理:
// History模式的简易实现
window.addEventListener('popstate', routeChange);
function navigate(path) {
history.pushState({}, "", path);
routeChange();
}
function routeChange() {
const path = window.location.pathname;
// 根据pathname来渲染不同的页面组件
routerView.innerHTML = routes[path] ? routes[path] : routes['404'];
}
// navigate('/user'); // 导航至用户页面
关于刷新404的问题
为什么history模式下会出现?
根据nginx的配置,当我们在地址栏输入 http://www.xxx.com 时,这时会打开我们 dist 目录下的 index.html 文件,然后我们再跳转路由进入到 http://www.xxx.com/login
关键在这里,当我们在 http://website.com/login 页执行刷新操作,会向真正的服务器发送请求资源,nginx location 是没有相关配置的,所以就会出现 404 的情况
为什么hash模式下不会出现?
router hash 模式我们都知道是用符号#表示的,如 http://website.com/#/login, hash 的值为 #/login
它的特点在于:hash 虽然出现在 URL 中,但不会被包括在内 HTTP 请求中,对服务端完全没有影响,因此改变 hash 不会重新加载页面
hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://website.com/#/login ...只有 http://website.com 会被包含在请求中 ,因此对于服务端来说,即使没有配置location,也不会返回404错误
简单来说: 前端打包后的 dist 包中,只有 index.html。所以,history 模式下发送的请求地址,服务端是找不到的。
hash模式的优缺
本文由“壹伴编辑器”提供技术支持
大致到这里就差不多了,又看见一篇写的比较好的文章,可以看一下。
单页应用
当我们在浏览器地址栏输入一个地址时,浏览器就会去服务端去请求内容。但每次点击一个链接,就去服务端请求,这样会有页面加载的等待。
后来慢慢就出现了单页应用,在第一次访问时,就把 html 文件,以及其他静态资源都请求到了客户端。之后的操作,只是利用 js 实现组件的展示和隐藏。除非需要刷新数据,才会利用 ajax 去请求。
但是纯粹的单页应用不方便管理,尤其是开发复杂应用的时候,需要有“多页面”的概念,并且很多用户习惯浏览器的前进后退的导航功能。
能不能有一种方法,可以在不向服务器发送请求的条件下,改变浏览器的 URL,以此来实现“多页面”概念?
答案是有,Vue Router 就是官方开发的一个插件,专门来做这件事。
URL 相关 API
最早改变 URL,但不向服务器发送请求的方式就是 hash。比如这种:
https://music.163.com/#/discover/toplist
同时浏览器也提供了一个事件来监听 hash 的改变,当 URL 的片段标识符更改时,将触发 hashchange 事件 (跟在#符号后面的URL部分,包括#符号)。
window.addEventListener('hashchange', function() {
console.log('The hash has changed!')
}, false);
后来 HTML5 发布,history 对象又增加了两个方法,用来改变浏览器的 URL。只是改变浏览器的访问记录栈,但是不会向服务器发起请求。
history.pushState(state, title[, url])
// 该方法会向浏览器会话的历史堆栈中添加一个状态。
history.replaceState(stateObj, title[, url])
//该方法与上一个方法类似,但区别是它会在历史堆栈中替换掉当前的记录。
const state = {
'page_id': 1, 'user_id': 5 }
const title = ''
const url = 'hello-world.html'
history.pushState(state, title, url)