路由的实现方式
vue可以通过vue-router实例来配置路由规则列表,指定路径path与组件component的对应关系。可以通过mode这一参数控制路由的实现模式,默认值是hash,基于hash的实现方式,如果显示设置为history,则会设为基于history API的实现方式.
面试简单回答:
1、hash: 为默认 hash 模式 ,使用 URL的hash来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。2、history : 这种模式充分利用
history.pushState
API 来完成 URL 跳转而无须重新加载页面。
1,利用监控锚点hash的变化实现前端路由思路(location.hash+hashchange事件
)
参考hash.html
hash方式是通过锚点来改变浏览器的URL,体现在URL后面会加上#,并且可以通过 window.onhashChange 来监听这一变化,从而我们可以建立好hash值和对应回调函数的映射关系,然后可以通过点击a标签,实现在不刷新页面情况下,通过ajax发送请求获取异步数据来改变页面的结构。
window.addEventListener("hashchange", function(){}, false)
-
触发hash值的变化有2种方法
(1), 通过a标签,设置href属性,当标签点击之后,地址栏会改变,同时会触发hashchange事件
<a href="#kaola">to KAOLA</a>
(2), 通过js直接赋值给location.hash,也会改变url,触发hashchange事件
location.hash="#kaola"
-
优点
- 无需向后端发起请求,在页面的 hash 值发生变化时,无需向后端发起请求,window.hashChange就可以监听事件的改变,并按规则加载相应的代码就好
- 兼容性较好,大部分浏览器支持
-
缺点
- '#'不太美观;
- 由于Hash对于服务端来说是不可见的,所以对于SEO不友好
2,利用History新API (pushState() 、replaceState() + popstate事件
)
参考history.html
HTML5中history对象,可以通过pushState() 方法或 replaceState() 方法可以修改url的地址, 并在popstate事件中能监听地址的改变,不同的是,手动的进行pushState()并不会触发popstate事件。
这两个API(pushState()和replaceState()) ,
相同之处是都会操作浏览器的历史记录,而不会引起页面的刷新。
不同之处在于,pushState会增加一条新的历史记录,而replaceState则会替换当前的历史记录。
这两个api,加上state改变触发的popstate事件,提供了单页应用的另一种路由方式。
需要特殊处理的两种方式
-
点击a链接
这种方式只需要在他的onclick事件先阻止他的默认跳转行为,然后获取他的url,调用pushState/replaceState改变URL,然后根据url和回调函数的映射关系,触发相应的动作 -
直接在脚本中调用pushState/replaceState
点击浏览器的前进/后退按钮,这里需要用到另一个事件,onpopState, 当激活浏览器历史记录时会被触发,注意这个事件不会被pushState/replaceState触发,这个事件回调会可以获取到当前路由下我们之前通过pushState/replaceState存入的信息,也可以拿到url信息,然后根据映射关系去执行回调。
history 扩展
- 后退一个记录window.history.back() 前进一个记录window.history.forward()
- 跳转第n次记录 window.history.go(n) 。 window.history.go(-1) 相等于window.history.back(),
- window.history.go(1) 相等于 window.history.forward(), window.history.go(0) 相等于 刷新
- pushState() 用于向history对象添加当前页面的记录,并且改变浏览器地址栏的URL。
- onpopstate事件,该事件在窗口历史记录改变时被触发。
两种方式的对比
基于Hash的路由,兼容性更好;
基于History API的路由,则更正式,可以设置与当前URL同源的任意URL,路径更直观。
另外,基于Hash的路由不需要对服务器做改动,基于History API的路由需要对服务器做一些改造,配置不同的路由都返回相同的页面。
调用 history.pushState() 比使用 hash 存在的优势:
- pushState 设置的 url 可以是同源下的任意 url ;而 hash 只能修改 # 后面的部分,因此只能设置当前 url 同文档的url
- pushState 设置的新的 url 可以与当前 url 一样,这样也会把记录添加到栈中;hash设置的新值不能与原来的一样,一样的值不会触发动作
- pushState 通过 stateObject参数可以将任何数据类型添加到记录中;hash 只能添加短字符串
- pushState 可以设置额外的 title 属性供后续使用
劣势:
- history 在刷新页面时,如果服务器中没有相应的响应或资源,就会出现404。因此,如果 URL 匹配不到任何静态资源,则应该返回同一个
- index.html 页面,这个页面就是你 app 依赖的页面 hash 模式下,仅 # 之前的内容包含在 http请求中,对后端来说,即使没有对路由做到全面覆盖,也不会报 404
路由匹配规则
路由的匹配规则是按照书写的顺序执行的,第一条匹配成功则不去匹配下一条,利用这一特性,可以在所有匹配路由的下面拦截其它所有路由:
//创建路由对象并配置路由规则
let router = new VueRouter({
routes:[
{path:'/',redirect:{name:"home"}}, // 重定向到主页
{name:'home',path:'/home',component:Home},
{name:'login',path:'/login',component:Login},
{path:'*',component:NotFound}, // 全不匹配的情况下,匹配NotFound组件
]
});
参考代码
hash.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<header>
<a href="#/">首页</a>
<a href="#/friend">朋友圈</a>
<a href="#/my">个人中心</a>
</header>
<div id="content">
</div>
</body>
<script>
window.onload = function(){
updateContent()
}
let contentObj = document.querySelector('#content')
window.addEventListener('hashchange',function(){
updateContent()
})
function updateContent(){
let hash = window.location.hash;
console.log(hash);
if(hash === '#/'){
contentObj.innerHTML = '首页'
}else if(hash === '#/friend'){
contentObj.innerHTML = '朋友圈'
}else if(hash === '#/my'){
contentObj.innerHTML = '个人中心'
}
}
</script>
</html>
history.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>前端路由实现</title>
</head>
<body>
<div>
<div class="nav">
<a href="javascript:void(0)" data-path="index">首页</a>
<a href="javascript:void(0)" data-path="news">新闻</a>
<a href="javascript:void(0)" data-path="about">关于</a>
</div>
<div id="router">
<!-- 内容加载区域 -->
</div>
</div>
<script>
(function () {
history.replaceState(null, null, ''); //最开始的状态,采用replace直接替换
document.querySelector('#router').innerHTML = '<p>首页</p>'
var allLinks = document.getElementsByTagName('a');
var urlArr = window.location.href.split('?');
var currentRouter = urlArr[urlArr.length - 1]
currentRouter = currentRouter ? currentRouter : 'index';
for(var i=0;i<allLinks.length;i++){
var allLinkItem = allLinks[i];
var path = allLinkItem.getAttribute('data-path');
allLinkItem.addEventListener('click', function () {
var text = this.text;
document.querySelector('#router').innerHTML = '<p>' + text + '</p>';
var url = this.getAttribute('data-path');
history.pushState(null, null, '?' + url);
// window.location.href = "http://localhost:3000/history.html?"+url;
})
if(path === currentRouter){
allLinkItem.click();
}
}
})()
</script>
</body>
</html>
Vue-router 跳转和 location.href 有什么区别
-
跳转是否刷新页面
使用 location.href= /url 来跳转,刷新了页面;
使用 history.pushState( /url ) ,无刷新页面,静态跳转; -
router跳转的优势
通过 router.push( /url ) 来跳转,使用了 diff 算法,实现了按需加载,减少了 dom 的消耗。
其实使用 router.push() 跳转和使用 history.pushState() 没什么差别的,因为 vue-router 就是用了 history.pushState() 。
参考链接 https://blog.csdn.net/u014298440/article/details/87467056
作者:Aniugel
链接:https://www.jianshu.com/p/4db4b191de06
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。