服务器之家:专注于服务器技术及软件下载分享
分类导航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服务器之家 - 编程语言 - JavaScript - vue.js - 详解vue的hash跳转原理

详解vue的hash跳转原理

2022-02-15 18:12mengyuhang4879 vue.js

这篇文章主要介绍了vue的hash跳转原理,帮助大家更好的理解和学习使用vue框架,感兴趣的朋友可以了解下

在new vueRouter的时候我们可以传入一个mode属性,他可以接收三个值:hash/history/abstract

详解vue的hash跳转原理

hash和history的区别

history的路径更美观一点 比如http://yoursite.com/user/id,history是基于pushState()来完成 URL 跳转而无须重新加载页面。 但是强制刷新还是会有问题(服务端来解决这个问题),所以history模式需要后端人员配合使用。

hash的路径会带有#,比如http://yoursite.com#/user/id

HashHistory

?
1
2
3
4
5
6
7
class VueRouter{
 constructor(options){
  this.matcher = createMatcher(options.routes || []);
//这里为了讲解hash模式 所以就不进行判断用户传进来的是哪种模式了
  this.history = new HashHistory(this);//this vue-router的实例
  }
}

源码这里创建了一个基类我们这里和源码统一,这个基类封装了三种模式公用的方法和属性,那么我们在这里创建一个HashHistory和基类History

?
1
2
3
4
5
6
7
8
9
10
11
12
13
import History from './base'
// hash路由
export default class HashHistory extends History{
 constructor(router){
  super(router); //继承调用父类 等于call
 }
}
// 路由的基类
export default class History {
 constructor(router){
  this.router = router;
 }
}

如果是hash路由,打开网站如果没有hash默认应该添加#/

?
1
2
3
4
5
6
7
8
9
10
11
12
13
import History from './base';
function ensureSlash(){
 if(window.location.hash){
  return
 }
 window.location.hash = '/'
}
export default class HashHistory extends History{
 constructor(router){
  super(router);
  ensureSlash(); // 确保有hash
 }
}

再看一下初始化的逻辑(上面的router.init函数)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
init(app){
  const history = this.history;
  // 初始化时,应该先拿到当前路径,进行匹配逻辑
 
  // 让路由系统过度到某个路径
  const setupHashListener = ()=> {
   history.setupListener(); // 监听路径变化
  }
  history.transitionTo( // 父类提供方法负责跳转
   history.getCurrentLocation(), // 子类获取对应的路径
   // 跳转成功后注册路径监听,为视图更新做准备
   setupHashListener
  )
}

这里我们要分别实现 transitionTo(基类方法)、 getCurrentLocation 、setupListener

getCurrentLocation实现

?
1
2
3
4
5
6
7
8
9
function getHash(){
 return window.location.hash.slice(1);
}
export default class HashHistory extends History{
 // ...
 getCurrentLocation(){
  return getHash();
 }
}

setupListener实现

?
1
2
3
4
5
6
7
8
9
export default class HashHistory extends History{
 // ...
 setupListener(){
  window.addEventListener('hashchange', ()=> {
   // 根据当前hash值 过度到对应路径
   this.transitionTo(getHash());
  })
 }
}

TransitionTo实现

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
export function createRoute(record, location) { // {path:'/',matched:[record,record]}
 let res = [];
 if (record) { // 如果有记录
  while(record){
   res.unshift(record); // 就将当前记录的父亲放到前面
   record = record.parent
  }
 }
 return {
  ...location,
  matched: res
 }
}
export default class History {
 constructor(router) {
  this.router = router;
  // 根据记录和路径返回对象,稍后会用于router-view的匹配
  this.current = createRoute(null, {
   path: '/'
  })
 }
 // 核心逻辑
 transitionTo(location, onComplete) {
  // 去匹配路径
  let route = this.router.match(location);
  // 相同路径不必过渡
  if(
   location === route.path &&
   route.matched.length === this.current.matched.length){
   return
  }
  //更新路由并且下面会提到改变根实例上的_route属性
  this.updateRoute(route)
  onComplete && onComplete();
 }
}
?
1
2
3
4
5
6
7
export default class VueRouter{
 // ...
 //做一个代理
 match(location){
  return this.matcher.match(location);
 }
}

macth方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
function match(location){ // 稍后根据路径找到对应的记录
 let record = pathMap[location]
 if (record) { // 根据记录创建对应的路由
 //参数:/about/a:{path:xx,component...},path:'/about/a'
  return createRoute(record,{
   path:location
  })
 }
 // 找不到则返回空匹配
 return createRoute(null, {
  path: location
 })
}

我们不难发现路径变化时都会更改current属性,我们可以把current属性变成响应式的,每次current变化刷新视图即可
在install方法中

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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(){
   return this._routerRoot._route;//上面刚进行双向数据绑定的
  }
 });
 Object.defineProperty(Vue.prototype,'$router',{ // 每个实例都可以获取router实例
  get(){
   return this._routerRoot._router;
  }
 })
 }

切换路由每次初始化时都需要调用更新_route的方法,因为install的时候把_route进行双向数据绑定,刚进来是没有this._router.history.current的,通过发布订阅方式来进行订阅和更新操作;在init方法中增加监听函数

?
1
2
3
history.listen((route) => { // 需要更新_route属性,出入一个函数
 app._route = route
});
?
1
2
3
4
5
6
7
8
9
10
11
12
13
export default class History {
 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跳转原理的资料请关注服务器之家其它相关文章!

原文链接:https://segmentfault.com/a/1190000039369103

延伸 · 阅读

精彩推荐
  • vue.js梳理一下vue中的生命周期

    梳理一下vue中的生命周期

    看过很多人讲vue的生命周期,但总是被绕的云里雾里,尤其是自学的同学,可能js的基础也不是太牢固,听起来更是吃力,那我就已个人之浅见,以大白话...

    CRMEB技术团队7992021-12-22
  • vue.jsVue2.x 项目性能优化之代码优化的实现

    Vue2.x 项目性能优化之代码优化的实现

    这篇文章主要介绍了Vue2.x 项目性能优化之代码优化的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋...

    优小U9632022-02-21
  • vue.js详解vue 表单绑定与组件

    详解vue 表单绑定与组件

    这篇文章主要介绍了vue 表单绑定与组件的相关资料,帮助大家更好的理解和学习使用vue框架,感兴趣的朋友可以了解下...

    Latteitcjz6432022-02-12
  • vue.jsVue2.x-使用防抖以及节流的示例

    Vue2.x-使用防抖以及节流的示例

    这篇文章主要介绍了Vue2.x-使用防抖以及节流的示例,帮助大家更好的理解和学习使用vue框架,感兴趣的朋友可以了解下...

    Kyara6372022-01-25
  • vue.jsVue多选列表组件深入详解

    Vue多选列表组件深入详解

    这篇文章主要介绍了Vue多选列表组件深入详解,这个是vue的基本组件,有需要的同学可以研究下...

    yukiwu6752022-01-25
  • vue.jsVue项目中实现带参跳转功能

    Vue项目中实现带参跳转功能

    最近做了一个手机端系统,其中遇到了父页面需要携带参数跳转至子页面的问题,现已解决,下面分享一下实现过程,感兴趣的朋友一起看看吧...

    YiluRen丶4302022-03-03
  • vue.js用vite搭建vue3应用的实现方法

    用vite搭建vue3应用的实现方法

    这篇文章主要介绍了用vite搭建vue3应用的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下...

    Asiter7912022-01-22
  • vue.jsVue中引入svg图标的两种方式

    Vue中引入svg图标的两种方式

    这篇文章主要给大家介绍了关于Vue中引入svg图标的两种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    十里不故梦10222021-12-31