欢迎大家来到IT世界,在知识的湖畔探索吧!
前言: 文章没有乱七八糟的图片,可在任意时刻食用,宝 ~~~, 懂你噢~~
众所周知,vue路由模式常见的有 history 和 hash 模式,但其实还有一种方式-abstract模式(了解一哈~)
别急,本文我们将重点逐步了解: 路由 + 几种路由模式 + 使用场景 + 思考 + freestyle
路由概念
路由的本质就是一种对应关系,根据不同的URL请求,返回对应不同的资源。那么url地址和真实的资源之间就有一种对应的关系,就是路由。
路由模式由来
对于 Vue 这类渐进式前端开发框架,为了构建 SPA(单页面应用),需要引入前端路由系统,这也就是 Vue-Router 存在的意义。而前端路由的核心,就在于 —— 改变视图的同时不会向后端发出请求。
为了达到这一目的,就产生了我们的 —— 路由模式
三种路由模式详解
hash模式
示例: www.ikun.com/#/kun,hash 的值为 #/kun。
概述:
地址栏 URL 中有 # 符号,后面就是 hash 值的变化(此 hash 不是密码学里的散列运算)。特点是:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端没有影响,改变后面的 hash 值,它不会向服务器发出请求,因此也就不会 刷新页面/重新加载页面。
每次 hash 值发生改变的时候,会触发 hashchange 事件。因此我们可以通过监听该事件,来知道 hash 值发生了哪些变化。
window.addEventListener('hashchange', ()=>{ // 通过 location.hash 获取到最新的 hash 值 console.log(location.hash); });
欢迎大家来到IT世界,在知识的湖畔探索吧!
使用:
欢迎大家来到IT世界,在知识的湖畔探索吧!<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>hash路由</title>
</head>
<body>
<ul>
<!-- 通过标签导航 声明式导航 -->
<!-- location.href='#/home' js方式进行导航切换 编程式导航 -->
<li><a href="#/home">首页</a></li>
<li><a href="#/about">关于</a></li>
</ul>
<div id="routerView"></div>
<script>
const routerRender = () => {
// 每次都置空hash
let html = ''
// 根据地址栏hash值的不同返回对应的资源
try {
// 如果hash值为空就给一个home
let hash = location.hash || '#/home'
html = component[hash.slice(2)]()
} catch (error) {
html = `<div>404</div>`
}
// 渲染到页面上
document.getElementById('routerView').innerHTML = html
}
const component = {
home() {
return `<div>home页面</div>`
},
about() {
return '<div>关于页面</div>'
}
}
window.onload = function () {
routerRender()
}
// 事件,监听地址栏中的hash值变化,实现回退
window.addEventListener('hashchange', routerRender)
</script>
</body>
</html>
优缺点:
优点:hash模式兼容性、安全性很强,刷新浏览器,页面还会存在
缺点:地址栏不优雅,有#存在,不利于seo(URL中的hash会影响搜索引擎的索引),记忆困难,
注意:
hash 模式既可以通过声明式导航,也可以通过编程式导航,上面的案例展示的是声明式导航。而下面将要讲到的 history 模式只能通过编程式导航实现,因为 history 是 js 对象。
使用锚点相关,hash模式中,使用普通的锚点链接和window.location.href和router-link 等跳转方式的话,包含#的片段标识符占用了#号与hash路由url相似,影响到了跳转。hash模式需要使用锚点的话,可以用scrollIntoView方法将目标元素滚动到可视区域
history模式
示例: www.ikun.com/kun,地址栏中没有#,路由地址跟正常的url一样
概述:
history —— 利用了 HTML5 History API 为浏览器的全局 history 对象增加的 pushState() 和 replaceState() 方法,可以对浏览器历史记录栈进行修改。(新增特性,所以浏览器需考虑IE9以及以下的版本带来的问题)。当地址栏的history状态发生变化时 切换了router-view渲染的组件 来”欺骗”用户 到达切换新网页的效果,需要后端配合。
History 还包括back、forward、go三个方法,对应浏览器的前进,后退,跳转操作。就是浏览器左上角的前进、后退等按钮进行的操作。
history.go(-2);//后退两次 history.go(2);//前进两次 history.back(); //后退 hsitory.forward(); //前进
只要历史栈有信息发生改变的话,window对象中提供的 popstate 事件就会监听到历史栈的改变,就会触发该事件。
欢迎大家来到IT世界,在知识的湖畔探索吧!history.pushState({},title,url); // 向历史记录中追加一条记录 history.replaceState({},title,url); // 替换当前页在历史记录中的信息。 window.addEventListener('popstate', function(e) { console.log(e) })
使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>history模式</title>
</head>
<body>
<ul>
<li><a href="/home">首页</a></li>
<li><a href="/about">关于</a></li>
</ul>
<div id="routerView"></div>
<script>
const component = {
home() {
return `<div>home页面</div>`
},
about() {
return '<div>关于页面</div>'
}
}
const routerRender = pathname => {
let html = ''
try {
html = component[pathname]()
} catch (error) {
html = `<div>404</div>`
}
document.getElementById('routerView').innerHTML = html
}
// history模式,它的路由导航,只能通过js来完成 , history它是js对象
// 给链接添加点击事件
document.querySelectorAll('a').forEach(node => {
node.addEventListener('click', function (evt) {
// 阻止a标签的默认跳转行为
evt.preventDefault()
// 跳转到指定的地址,能回退
// history.pushState
// 跳转到指定持址,不能回退
// history.replaceState
history.pushState({}, null, this.href)
// 渲染
routerRender(this.href.match(//(\w+)$/)[1])
})
})
// 在网页加载完毕后立刻执行的操作,即当 HTML 文档加载完毕后,立刻渲染 home 中的标签
window.onload = () => {
routerRender('home')
}
// 回退
window.addEventListener('popstate', function () {
routerRender(location.pathname.slice(1))
})
</script>
</body>
</html>
优缺点:
缺点:history模式,兼容性较差,刷新页面,页面会404,需要服务器端配置支持
优点:地址栏更优雅,方便记忆,对比hash模式下更支持seo
刷新页面出现404原因以及解决:
原因:
因为vue项目中路由hash模式改为了history模式,由于hash模式时url带的#号后面是哈希值不会作为url的一部分发送给服务器,而history模式下当刷新页面之后浏览器会直接去请求服务器,而服务器没有这个路由,于是就出现404。
因为我们的应用是单页客户端应用,当使用 history 模式时,URL 就像正常的 url,可以直接访问www.ikun.com/kun/love,但是因为 vue-router 设置的路径不是真实存在的路径,所以刷新就会返回404错误
解决方法(后端配合,这里讲的是nginx配置):
在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。也就是在服务端修改404错误页面的配置路径,让其指向到index.html
方法一:
location /{
root /data/nginx/html;
index index.html index.htm;
if (!-e $request_filename) {
rewrite ^/(.*) /index.html last;
break;
}
}
方法二: (vue.js官方教程里提到的https://router.vuejs.org/zh-cn/essentials/history-mode.html)
server {
listen 8888;#默认端口是80,如果端口没被占用可以不用修改
server_name localhost;
root E:/vue/my_project/dist;#vue项目的打包后的dist
location / {
try_files $uri $uri/ @router;#需要指向下面的@router否则会出现vue的路由在nginx中刷新出现404
index index.html index.htm;
}
#对应上面的@router,主要原因是路由的路径资源并不是一个真实的路径,所以无法找到具体的文件
#因此需要rewrite到index.html中,然后交给路由在处理请求资源
location @router {
rewrite ^.*$ /index.html last;
}
#.......其他部分省略
}
abstract模式
abstract模式—-适用于所有JavaScript环境,例如服务器端使用Node.js。如果没有浏览器API,路由器将自动被强制进入此模式。
abstract 是一种与浏览器分离的路由模式,本身是用来在不支持浏览器API的环境中,充当fallback,而不论是hash还是history模式都会对浏览器上的url产生作用。
利用abstract这种与浏览器分离的路由模式,我们可以在已存在的路由页面中内嵌其他的路由页面,而保持在浏览器当中依旧显示当前页面的路由path。
使用场景
history — 颜值性(强迫症患者推荐,更友好的URL格式、SEO支持)
一般场景下,hash 和 history 都可以,除非你更在意颜值,# 符号夹杂在 URL 里看起来确实有些不太美丽。我们可以用路由的 history 模式,充分利用 history.pushState API 来完成URL 跳转而无须重新加载页面。如果需要更好的SEO支持(使用hash模式,URL中的hash会影响搜索引擎的索引,所以不利于seo),并且愿意进行服务器端配置,history 模式是很好的选择
调用 history.pushState() 相比于直接修改 hash,还存在以下优势:
1、pushState() 设置的新 URL 可以是与当前 URL 同源的任意 URL;而 hash 只可修改 #后面的部分,因此只能设置与当前 URL 同文档的 URL;
2、pushState() 设置的新 URL 可以与当前 URL 一模一样,这样也会把记录添加到栈中;而 hash设置的新值必须与原来不一样才会触发动作将记录添加到栈中;
3、pushState() 通过 stateObject 参数可以添加任意类型的数据到记录中;而 hash 只可添加短字符串;
4、pushState() 可额外设置 title 属性供后续使用。
hash —- 安全兼容,不需要后端协助
SPA 虽然在浏览器里游刃有余,但真要通过 URL 向后端发起 HTTP 请求时,两者的差异就来了。尤其在用户手动输入 URL 后回车,或者刷新(重启)浏览器的时候。
hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 www.ikun.com ,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。
abstract模式 —- 特殊场景
abstract模式—-适用于所有JavaScript环境(浏览器端和服务端),例如服务器端使用Node.js。
像上文说的,可以利用abstract这种与浏览器分离的路由模式,在已存在的路由页面中内嵌其他的路由页面,而保持在浏览器当中依旧显示当前页面的路由path。
小结
选择使用 hash 模式还是 history 模式,主要取决于你的具体需求和项目要求。如果你的应用不需要很考虑SEO,并且不涉及服务器端的重定向和处理,Hash模式是一种简单且易于使用的选择。如果你需要更友好的URL格式、更好的SEO支持,并且愿意进行服务器端配置,那么history 模式是更好的选择。
结合自身例子,对于一般形式的 Web 开发场景,个人比较习惯用用 history 模式,只需在后端(Apache 或 Nginx)进行简单的路由配置,同时搭配前端路由的 404 页面支持。
关于history和hash模式思考:
看了这两种的模式的基本原理,你会发现,hash 模式和 history 模式都属于基于浏览器自身的特性相关的API和特性进行上层搭建,Vue-Router 只是利用了这两个特性(通过调用浏览器提供的接口)来实现前端路由。所以,对于我们看待一个新知识的时候,我们刚开始会觉得它们是一个金字塔,但到最后我们会发现这个金字塔还是这个金字塔,只不过我们把他倒转了。空中楼阁的那颗隐藏的柱子(本质)被我们找到了,而发现了这个“柱子”我们就已经要了解上层建筑的怎么搭建起来的了。
作者:KAIHUA
链接:https://juejin.cn/post/
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/88688.html