zoukankan      html  css  js  c++  java
  • vue-router 结合源码分析原理

    路由响应过程:
    1. 浏览器发出请求

    2. 服务器监听到num端口(或443)有请求过来,并解析url路径

    3. 根据服务器的路由配置,返回相应信息(可以是 html 字串,也可以是 json 数据,图片等)

    4. 浏览器根据数据包的 Content-Type 来决定如何解析数据

    一般的vueRouter的代码模式是这样的:
    let router = new Router({
      mode: 'history|hash|abstract',
      routes: [
        { // 默认页
          path: '*',
          redirect: to => {
            return '/'
          },
          meta: {
            status: ***
          }
        },
        {  
          path: '/',
          name: '****',
          component: ****,
          meta: {
            status: ***
          }
        },
      ],
      beforeEnter: (to, from, next) => {}),
      scrollBehavior: fun()
    })

    可以看到的是使用Router这个类进行实例化【new Router(options)】

    在使用vueRouter的时候,我们会在项目中使用Vue.use(Router)安装,它会加载VueRouter中的 install 方法使得所有组件都可以使用router的实例(this.$router/this.$route 在install的时候实际上完成一些初始化的工作

    (源码install.js)

    1)在vue.prototype上注册一个$router/$route的实例

      Vue.mixin({
        beforeCreate () {
          if (isDef(this.$options.router)) {
            this._routerRoot = this
            this._router = this.$options.router
    
      Object.defineProperty(Vue.prototype, '$router', {
        get () { return this._routerRoot._router }
      })
    
      Object.defineProperty(Vue.prototype, '$route', {
        get () { return this._routerRoot._route }
      })

    2)全局注册RouterView, RouterLink这两个组件

     Vue.component('RouterView', View)
     Vue.component('RouterLink', Link)
     
    分为三种模式: hash, history(h5), abstract

    (源码index.js)

    switch (mode) {
      case 'history':
        this.history = new HTML5History(this, options.base)
        break
      case 'hash':
        this.history = new HashHistory(this, options.base, this.fallback)
        break
      case 'abstract':
        this.history = new AbstractHistory(this, options.base)
        break
      default:
        if (process.env.NODE_ENV !== 'production') {
          assert(false, `invalid mode: ${mode}`)
        }
    }
     
    三种模式的简单描述: 

    a)hash

    常见形式:http(https)://xxxxxx/#/xxxx

    在h5之前浏览器不支持popState(window),pushState(history)和 replaceState(history)这几个事件,因此是通过hash值来改变路由,后面 hash 值的变化,并不会导致浏览器向服务器发出请求,浏览器不发出请求,也就不会刷新页面。另外每次 hash 值的变化,还会触发hashchange 这个事件,通过这个事件我们就可以知道 hash 值发生了哪些变化。然后我们便可以监听hashchange来实现更新页面部分内容的操作:

    (源码hash.js)

     // supportsPushState用于用于判断浏览器是否支持h5 
     window.addEventListener(supportsPushState ? 'popstate' : 'hashchange', () => {
      const current = this.current
      if (!ensureSlash()) {
        return
      }
      this.transitionTo(getHash(), route => {
        if (supportsScroll) {
          handleScroll(this.router, route, current, true)
        }
        if (!supportsPushState) { // 如果不支持pushState 就使用window.location.replace(getUrl(path))
            replaceHash(route.fullPath)
        }
      })
    })

    b)history

    在h5之后,得到浏览器的支持就可以使用history模式了,在history模式下路由的改变会触发popstate事件,因此history模式原理也是对popstate事件的监听,然后做出相应操作。

    (源码html5.js)

    window.addEventListener('popstate', e => {
        const current = this.current
        // Avoiding first `popstate` event dispatched in some browsers but first
        // history route not updated since async guard at the same time.
        const location = getLocation(this.base)
        if (this.current === START && location === initLocation) {
          return
        }
        this.transitionTo(location, route => {
          if (supportsScroll) {
            handleScroll(router, route, current, true)
          }
        })
      })
    

    c)abstract

    abstract 模式是用于原生开发(非浏览器typeof window=== 'undefined')的情况下,这就意味着不能使用window对象;另外由于在原生app中,页面储存一个数组栈中,它记录着页面的的访问记录,因此在js中最简单的就是定义数组进行模仿。

    (源码abstrack.js)

    constructor (router: Router, base: ?string) {
      super(router, base)
      this.stack = [] // 定义一个stack数组,用于存储路由
      this.index = -1 // 记录每个路由在stack中的索引
    }
    
     
    关于popstate,pushState, replaceState: 

    1)window.popstate,history.pushState,history.replaceState是h5中新增的几个方法。

    2)hash模式情况下路由的该变会触发window.hashtate,history模式下会触发window.popstate事件。

    3)history.pushState()/replaceState() 会修改url ,不会使得页面更新,也不会触发window.popstate事件。

      在history模式下使得页面url与代码中路由地址相同

    4)history.back() /go(),window.location.hash 都会使得页面改变,触发window.popstate事件。

      对此事件进行拦截处理一些事情(参数接收,页面位置记录)

        window.addEventListener(supportsPushState ? 'popstate' : 'hashchange', () => {
          const current = this.current
          if (!ensureSlash()) {
            return
          }
          this.transitionTo(getHash(), route => {
            if (supportsScroll) {
              handleScroll(this.router, route, current, true)
            }
            if (!supportsPushState) {
              replaceHash(route.fullPath)
            }
          })
        })

    5)使用导航的时候其实都是使用的 this.history.push()/ go() /replace() 进行页面切换。

      push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
        this.history.push(location, onComplete, onAbort)
      }
    
      replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
        this.history.replace(location, onComplete, onAbort)
      }
    
      go (n: number) {
        this.history.go(n)
      }
    
      back () {
        this.go(-1)
      }
    forward () { this.go(1) }

      

    https://segmentfault.com/a/1190000015123061

    https://zhuanlan.zhihu.com/p/24574970

      

  • 相关阅读:
    HDU 2176 取(m堆)石子游戏 (尼姆博奕)
    HDU 1846 Brave Game (巴什博弈)
    HDU-1025 Constructing Roads In JGShining's Kingdom
    FOJ有奖月赛-2015年11月 Problem B 函数求解
    FOJ有奖月赛-2015年11月 Problem A
    JXNU acm选拔赛 不安全字符串
    JXNU acm选拔赛 涛神的城堡
    JXNU acm选拔赛 涛涛的Party
    JXNU acm选拔赛 壮壮的数组
    JXNU acm选拔赛 最小的数
  • 原文地址:https://www.cnblogs.com/evaling/p/10304466.html
Copyright © 2011-2022 走看看