详解vue的hash跳转原理
在newvueRouter的时候我们可以传入一个mode属性,他可以接收三个值:hash/history/abstract
hash和history的区别
history的路径更美观一点比如http://yoursite.com/user/id,history是基于pushState()来完成URL跳转而无须重新加载页面。但是强制刷新还是会有问题(服务端来解决这个问题),所以history模式需要后端人员配合使用。
hash的路径会带有#,比如http://yoursite.com#/user/id
HashHistory
classVueRouter{
constructor(options){
this.matcher=createMatcher(options.routes||[]);
//这里为了讲解hash模式所以就不进行判断用户传进来的是哪种模式了
this.history=newHashHistory(this);//thisvue-router的实例
}
}
源码这里创建了一个基类我们这里和源码统一,这个基类封装了三种模式公用的方法和属性,那么我们在这里创建一个HashHistory和基类History
importHistoryfrom'./base'
//hash路由
exportdefaultclassHashHistoryextendsHistory{
constructor(router){
super(router);//继承调用父类等于call
}
}
//路由的基类
exportdefaultclassHistory{
constructor(router){
this.router=router;
}
}
如果是hash路由,打开网站如果没有hash默认应该添加#/
importHistoryfrom'./base';
functionensureSlash(){
if(window.location.hash){
return
}
window.location.hash='/'
}
exportdefaultclassHashHistoryextendsHistory{
constructor(router){
super(router);
ensureSlash();//确保有hash
}
}
再看一下初始化的逻辑(上面的router.init函数)
init(app){
consthistory=this.history;
//初始化时,应该先拿到当前路径,进行匹配逻辑
//让路由系统过度到某个路径
constsetupHashListener=()=>{
history.setupListener();//监听路径变化
}
history.transitionTo(//父类提供方法负责跳转
history.getCurrentLocation(),//子类获取对应的路径
//跳转成功后注册路径监听,为视图更新做准备
setupHashListener
)
}
这里我们要分别实现transitionTo(基类方法)、getCurrentLocation、setupListener
getCurrentLocation实现
functiongetHash(){
returnwindow.location.hash.slice(1);
}
exportdefaultclassHashHistoryextendsHistory{
//...
getCurrentLocation(){
returngetHash();
}
}
setupListener实现
exportdefaultclassHashHistoryextendsHistory{
//...
setupListener(){
window.addEventListener('hashchange',()=>{
//根据当前hash值过度到对应路径
this.transitionTo(getHash());
})
}
}
TransitionTo实现
exportfunctioncreateRoute(record,location){//{path:'/',matched:[record,record]}
letres=[];
if(record){//如果有记录
while(record){
res.unshift(record);//就将当前记录的父亲放到前面
record=record.parent
}
}
return{
...location,
matched:res
}
}
exportdefaultclassHistory{
constructor(router){
this.router=router;
//根据记录和路径返回对象,稍后会用于router-view的匹配
this.current=createRoute(null,{
path:'/'
})
}
//核心逻辑
transitionTo(location,onComplete){
//去匹配路径
letroute=this.router.match(location);
//相同路径不必过渡
if(
location===route.path&&
route.matched.length===this.current.matched.length){
return
}
//更新路由并且下面会提到改变根实例上的_route属性
this.updateRoute(route)
onComplete&&onComplete();
}
}
exportdefaultclassVueRouter{
//...
//做一个代理
match(location){
returnthis.matcher.match(location);
}
}
macth方法
functionmatch(location){//稍后根据路径找到对应的记录
letrecord=pathMap[location]
if(record){//根据记录创建对应的路由
//参数:/about/a:{path:xx,component...},path:'/about/a'
returncreateRoute(record,{
path:location
})
}
//找不到则返回空匹配
returncreateRoute(null,{
path:location
})
}
我们不难发现路径变化时都会更改current属性,我们可以把current属性变成响应式的,每次current变化刷新视图即可
在install方法中
install(Vue){
Vue.mixin({//给所有组件的生命周期都增加beforeCreate方法
beforeCreate(){
if(this.$options.router){
//调用Vue类中双向数据绑定方法
Vue.util.defineReactive(this,'_route',this._router.history.current);
}
}
});
//$route和$router方法这两个方法仅仅是vue中最常见的代理仅仅是为了更加方便
Object.defineProperty(Vue.prototype,'$route',{//每个实例都可以获取到$route属性
get(){
returnthis._routerRoot._route;//上面刚进行双向数据绑定的
}
});
Object.defineProperty(Vue.prototype,'$router',{//每个实例都可以获取router实例
get(){
returnthis._routerRoot._router;
}
})
}
切换路由每次初始化时都需要调用更新_route的方法,因为install的时候把_route进行双向数据绑定,刚进来是没有this._router.history.current的,通过发布订阅方式来进行订阅和更新操作;在init方法中增加监听函数
history.listen((route)=>{//需要更新_route属性,出入一个函数
app._route=route
});
exportdefaultclassHistory{
constructor(router){
//...
this.cb=null;
}
listen(cb){
this.cb=cb;//注册函数
}
updateRoute(route){
this.current=route;
this.cb&&this.cb(route);//更新current后更新_route属性
}
}
以上就是详解vue的hash跳转原理的详细内容,更多关于vue的hash跳转原理的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。