Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vue-router 实现 -- HTML5History #26

Open
muwoo opened this issue Jun 4, 2018 · 0 comments
Open

vue-router 实现 -- HTML5History #26

muwoo opened this issue Jun 4, 2018 · 0 comments

Comments

@muwoo
Copy link
Owner

muwoo commented Jun 4, 2018

vue-router通过设置mode = history可以在浏览器支持 history 模式的情况下,用来开启 HTML5History 模式。我们知道在install挂载的时候,会在beforeCreate钩子内执行init方法:

init () {
    // ...
    if (history instanceof HTML5History) {
      history.transitionTo(history.getCurrentLocation())
    }
    // ...
}

当判断当前模式是 HTML5History的时候,会执行 history 对象上的 transitionTo方法。接下来我们主要分析 HTML5History 的主要功能。

constructor

vue-router实例化过程中,执行对 HTML5History 的实例化:

this.history = new HTML5History(this, options.base)

此时会执行 HTML5History 中的 constructor:

  constructor (router: Router, base: ?string) {
    // 实现 base 基类中的构造函数
    super(router, base)
    
    // 滚动信息处理
    const expectScroll = router.options.scrollBehavior
    const supportsScroll = supportsPushState && expectScroll

    if (supportsScroll) {
      setupScroll()
    }

    const initLocation = getLocation(this.base)
    window.addEventListener('popstate', e => {
      const current = this.current

      // 避免在有的浏览器中第一次加载路由就会触发 `popstate` 事件
      const location = getLocation(this.base)
      if (this.current === START && location === initLocation) {
        return
      }
      // 执行跳转动作
      this.transitionTo(location, route => {
        if (supportsScroll) {
          handleScroll(router, route, current, true)
        }
      })
    })
  }

可以看到在这种模式下,初始化作的工作相比 hash 模式少了很多,只是调用基类构造函数以及初始化监听事件,不需要再做额外的工作。由于在上篇文章中已经介绍了 transitionToconfirmTransition。这里不再过多介绍了。到这里好像也就没什么,那么我们来看几个之前没介绍的一下 API 吧

一些API

vue-router中我们通常会通过这种方式操作路由信息:

router.push(location, onComplete?, onAbort?)
router.replace(location, onComplete?, onAbort?)
router.go(n)
router.back()
router.forward()

具体的可以参考这里编程式导航
来一起看一下 vue-router 的统一实现:

  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)
  }

可以看到,也都是调用了history内部的方法。

你也许注意到 router.pushrouter.replacerouter.gowindow.history.pushStatewindow.history.replaceStatewindow.history.go好像, 实际上它们确实是效仿 window.history API 的。
因此,如果你已经熟悉 Browser History APIs,那么在 Vue Router 中操作 history 就是超级简单的。
还有值得提及的,Vue Router 的导航方法 (push、 replace、 go) 在各类路由模式 (history、 hash 和 abstract) 下表现一致。

举个例子🌰:

// go
go (n: number) {
  window.history.go(n)
}

// push最终也是调用的history API
history.pushState({ key: _key }, '', url)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant