详解vue的hash跳转原理

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

hash和history的区别

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

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

HashHistory

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

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

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默认应该添加#/

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函数)

init(app){
  const history = this.history;
  // 初始化时,应该先拿到当前路径,进行匹配逻辑

  // 让路由系统过度到某个路径
  const setupHashListener = ()=> {
   history.setupListener(); // 监听路径变化
  }
  history.transitionTo( // 父类提供方法负责跳转
   history.getCurrentLocation(), // 子类获取对应的路径
   // 跳转成功后注册路径监听,为视图更新做准备
   setupHashListener
  )
}

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

getCurrentLocation实现

function getHash(){
 return window.location.hash.slice(1);
}
export default class HashHistory extends History{
 // ...
 getCurrentLocation(){
  return getHash();
 }
}

setupListener实现

export default class HashHistory extends History{
 // ...
 setupListener(){
  window.addEventListener('hashchange', ()=> {
   // 根据当前hash值 过度到对应路径
   this.transitionTo(getHash());
  })
 }
}

TransitionTo实现

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();
 }
}
export default class VueRouter{
 // ...
 //做一个代理
 match(location){
  return this.matcher.match(location);
 }
}

macth方法

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方法中

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方法中增加监听函数

history.listen((route) => { // 需要更新_route属性,出入一个函数
 app._route = route
});
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跳转原理的资料请关注我们其它相关文章!

(0)

相关推荐

  • 区分vue-router的hash和history模式

    一.概念 为了构建 SPA(单页面应用),需要引入前端路由系统,这也就是 Vue-Router 存在的意义. 前端路由的核心,就在于:改变视图的同时不会向后端发出请求. 为了达到这种目的,浏览器当前提供了以下两种支持: 1.hash--即地址栏 URL 中的 # 符号(此 hash 不是密码学里的散列运算). 比如这个 URL:http://www.abc.com/#/hello,hash 的值为 #/hello. 它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中

  • Vue-router 中hash模式和history模式的区别

    Vue-router 中hash模式和history模式的关系 在vue的路由配置中有mode选项 最直观的区别就是在url中 hash 带了一个很丑的 # 而history是没有#的 mode:"hash";   mode:"history"; hash模式和history模式的不同 对于vue这类渐进式前端开发框架,为了构建 SPA(单页面应用),需要引入前端路由系统,这也就是 Vue-Router 存在的意义.前端路由的核心,就在于 -- 改变视图的同时不会向

  • vue的hash值原理也是table切换实例代码

    我希望大家敲一遍 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style> .pages>div{display: none;} </style> </head> <body> <p> <a href="#/" rel="

  • Vue-router中hash模式与history模式的区别详解

    VUE路由的hash模式与history模式的区别,这个也是面试常问的问题,这个题其实就是考验你的开发经验是否属实. 小白回答:hash模式url带#号,history模式不带#号. 大牛解答: 形式上:hash模式url里面永远带着#号,开发当中默认使用这个模式.如果用户考虑url的规范那么就需要使用history模式,因为history模式没有#号,是个正常的url,适合推广宣传: 功能上:比如我们在开发app的时候有分享页面,那么这个分享出去的页面就是用vue或是react做的,咱们把这个

  • 在Vue中实现随hash改变响应菜单高亮

    情景 Vue+Element 实现管理页面菜单栏, 点击菜单时 router 改变 hash 访问不同子组件. 但是改变 hash 时菜单栏展开状态和 highlight 并不会同步, 需要手动实现. Try Try See 第一反应是通过 onhashchange 监听 hash 的变化, 讲 location.hash.slice(2) 推给 menu 的 default-active 即可. 此时通过手动输入 url 或者前进后退时均可正常加载对应状态,但是通过组件中的 link 访问时,

  • vue vue-Router默认hash模式修改为history需要做的修改详解

    主要是因为活动页会存在pc端的时候未登录的用户也需要访问的问题,因为未登录用户在活动页面进行操作的时候会触发到登录事件,然后我们实现的方式是通过接口来判断,该接口标记的是一个upn的值 然后登录的时候是单点登录,不知道是否回调地址不支持vue形式下hash模式的路由,因而自动忽视了后面的#路径 然后我查了一下一般回调以后#后都会默认为书签,我转义了然而还是只能职别#之前的路径 由于不是很清楚登录单点那一块而且他们暂时实现没有什么业务问题(当然开始~~就是不稳定,现在有时候还是会有不稳定的问题)所

  • 一文了解vue-router之hash模式和history模式

    当前版本: 3.0.3 类目录: src/history/base.js hash模式 即地址栏 URL 中的 # 符号(此 hash 不是密码学里的散列运算).比如这个 URL: http://www.abc.com/#/hello ,hash 的值为 #/hello.它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面. history模式 利用了 HTML5 History Interface 中新增的

  • vue-cli3中配置alias和打包加hash值操作

    1.之前在项目测试环境打包的时候,js文件打包出来没有hash值,但是生产环境打包出来却又hash值 当时只配置了 filenameHashing: true,这样是不够的 后来在chainWebpack中配置config.output.filename('[name].[hash].js').end(),解决了该问题 2.配置alias可以在引入文件的时候不用写很长的相对路径 步骤: 先引入path模块 const path = require('path') function resolve

  • 基于vue hash模式微信分享#号的解决

    看代码吧~ // 问题描述在微信中分享到朋友圈或好友时,分享出去的路由被破坏,打开分享的链接,路由中的"#"会被去掉并追加?fromTimeline之类的后缀参数,这就造成了分享出去的链接只能进入首页,无法正常跳转到其他路由. // 获取签名 this.$ajax.post(this.apiUrl+"/api/wxShare/getWxConfig", this.$qs.stringify({"url":window.location.href.

  • 详解vue的hash跳转原理

    在new vueRouter的时候我们可以传入一个mode属性,他可以接收三个值:hash/history/abstract hash和history的区别 history的路径更美观一点 比如http://yoursite.com/user/id,history是基于pushState()来完成 URL 跳转而无须重新加载页面. 但是强制刷新还是会有问题(服务端来解决这个问题),所以history模式需要后端人员配合使用. hash的路径会带有#,比如http://yoursite.com#/

  • 详解Vue的异步更新实现原理

    最近面试总是会被问到这么一个问题:在使用vue的时候,将for循环中声明的变量i从1增加到100,然后将i展示到页面上,页面上的i是从1跳到100,还是会怎样?答案当然是只会显示100,并不会有跳转的过程. 怎么可以让页面上有从1到100显示的过程呢,就是用setTimeout或者Promise.then等方法去模拟. 讲道理,如果不在vue里,单独运行这段程序的话,输出一定是从1到100,但是为什么在vue中就不一样了呢? for(let i=1; i<=100; i++){ console.

  • 详解vue的数据binding绑定原理

    自从angular火了以后,各种mvc框架喷涌而出,angular虽然比较火,但是他的坑还是蛮多的,还有许多性能问题被人们吐槽.比如坑爹的脏检查机制,数据binding是受人喜爱的,脏检查就有点-性能低下了.有时候改了一个地方,脏循环要循环多次来保证数据是不是真的变了和是否停止变化了.这样性能就很低了.于是人们开始钻研新的双向数据binding的方法.尤大的vue binding就是本人蛮喜欢的一种实现方式,本文跟随尤大的一个例子来详解vue的数据binding的原理. 数据binding,一般

  • 详解vue computed的缓存实现原理

    目录 初始化 computed 依赖收集 派发更新 总结一下 本文围绕下面这个例子,讲解一下computed初始化及更新时的流程,来看看计算属性是怎么实现的缓存,及依赖是怎么被收集的. <div id="app"> <span @click="change">{{sum}}</span> </div> <script src="./vue2.6.js"></script> &

  • 详解Vue监听数据变化原理

    本人最近在学习Vue,从网上查询了很多关于Vue监听数据变化原理,稍微整理精简一下做下分享. 浅度监听 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>浅度监听</title> <meta name="viewport" content="width=device-wi

  • 详解vue 路由跳转四种方式 (带参数)

    1.  router-link 1. 不带参数 <router-link :to="{name:'home'}"> <router-link :to="{path:'/home'}"> //name,path都行, 建议用name // 注意:router-link中链接如果是'/'开始就是从根路由开始,如果开始不带'/',则从当前路由开始. 2.带参数 <router-link :to="{name:'home', para

  • 详解Vue中的MVVM原理和实现方法

    下面由我阿巴阿巴的详细走一遍Vue中MVVM原理的实现,这篇文章大家可以学习到: 1.Vue数据双向绑定核心代码模块以及实现原理 2.订阅者-发布者模式是如何做到让数据驱动视图.视图驱动数据再驱动视图 3.如何对元素节点上的指令进行解析并且关联订阅者实现视图更新 一.思路整理 实现的流程图: 我们要实现一个类MVVM简单版本的Vue框架,就需要实现一下几点: 1.实现一个数据监听Observer,对数据对象的所有属性进行监听,数据发生变化可以获取到最新值通知订阅者. 2.实现一个解析器Compi

  • 详解vue 组件的实现原理

    组件机制的设计,可以让开发者把一个复杂的应用分割成一个个功能独立组件,降低开发的难度的同时,也提供了极好的复用性和可维护性.本文我们一起从源码的角度,了解一下组件的底层实现原理. 组件注册时做了什么? 在Vue中使用组件,要做的第一步就是注册.Vue提供了全局注册和局部注册两种方式. 全局注册方式如下: Vue.component('my-component-name', { /* ... */ }) 局部注册方式如下: var ComponentA = { /* ... */ } new Vu

  • 详解Vue数据驱动原理

    前言 Vue区别于传统的JS库,例如JQuery,其中一个最大的特点就是不用手动去操作DOM,只需要对数据进行变更之后,视图也会随之更新. 比如你想修改div#app里的内容: /// JQuery <div id="app"></div> <script> $('#app').text('lxb') </script> <template> <div id="app">{{ message }

  • 详解vue路由

    前端路由和后端路由: 后端路由:对于普通的网站,所有的超链接都是url地址,所有url都对应服务器上对应的资源 前端路由:对于单页面应用程序来说,主要通过url的hash(#)来实现不同页面的切换,同时hash还有一个特点HTTP请求中不会包含hash相关的内容,所以单页面程序中的页面跳转主要用hash实现 在单页面应用程序中这种通过hash来改变页面的方式称作前端路由区别于后端路由 路由的使用 1.创建一个路由对象,当导入vue-router包之后,在window全局对象中就有一个路由的构造函

随机推荐