从Vue-router到html5的pushState

最近在用vue的时候忽然想到一个问题javascript

首先,咱们知道vue实现的单页应用中通常不会去刷新页面,由于刷新以后页面中的vuex数据就不见了。 其次,咱们也知道通常状况下,url变动的时候,好比指定location.href、history.push、replace等,页面就会刷新。html

那么问题来了,vue页面的页面跳转时怎么实现的?没刷新页面么?没刷新页面,又要改变url,加载新内容怎么作的?vue

去翻了一下vue-router的源码,找到这样一段html5

export class HTML5History extends History {
   ...

  push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
    const { current: fromRoute } = this
    this.transitionTo(location, route => {
      pushState(cleanPath(this.base + route.fullPath))
      handleScroll(this.router, route, fromRoute, false)
      onComplete && onComplete(route)
    }, onAbort)
  }

  replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
    const { current: fromRoute } = this
    this.transitionTo(location, route => {
      replaceState(cleanPath(this.base + route.fullPath))
      handleScroll(this.router, route, fromRoute, false)
      onComplete && onComplete(route)
    }, onAbort)
  }
  ...
}

再看看方法内部java

export function pushState (url?: string, replace?: boolean) {
  saveScrollPosition()
  // try...catch the pushState call to get around Safari
  // DOM Exception 18 where it limits to 100 pushState calls
  const history = window.history
  try {
    if (replace) {
      history.replaceState({ key: _key }, '', url)
    } else {
      _key = genKey()
      history.pushState({ key: _key }, '', url)
    }
  } catch (e) {
    window.location[replace ? 'replace' : 'assign'](url)
  }
}

答案就是html5在history中新增长的方法:pushState和replaceState。这两个又是干啥的呢?(两个十分相似,如下以pushState为例说明,区别和push与replace一致)vue-router

HTML5的pushState()

首先看看这个是干什么的 pushState方法就是向history中push一条记录,更改页面url,可是不刷新页面,不刷新页面,不刷新页面。不刷新页面,这点很关键,这和下面的操做很类似vuex

window.location.href = window.location.href + '#a=b'

知道干吗的了,再看看API怎么用的dom

history.pushState(state, title, url);
  • state是一个对象,具体内容除了最大640KB以外没有别的限制,好比在vue中是生成了一个key存进去了。若无特殊须要传个null便可。这个state能够在history或者popstate的事件中看到 history中的 popstate中的 this

  • title这个参数目前没什么用处,多是给之后预留的参数,暂时用null就行了url

  • url很明显,就是替换后的url了。url能够接受绝对地址和相对地址,设置绝对地址的时候,要保证域名和当前域名一致,不然汇报以下错误

Uncaught DOMException: Failed to execute 'pushState' on 'History': A history state object with URL 'https://www.baidu.com/' cannot be created in a document with origin 'https://mocard-aliyun1.chooseway.com:8443' and URL 'https://mocard-aliyun1.chooseway.com:8443/views/h5/indexasdasd'.
    at History.pushState (https://aixuedaiimg.oss-cn-hangzhou.aliyuncs.com/static/m/js/alog/v1.0.0/alog.min.js:1:23259)
    at <anonymous>:1:9

HTML5的popstate()

  • popstate与pushState相对应,主要在页面url变动的时候触发,通常绑定在window对象下
window.addEventListener('popstate', e => {
  console.log('popstate', )
})

前面pushState中传入的state对象,能够在这边接收到,并根据须要去作一些处理。

说到这,vue-router是怎么实现页面“刷新”但不刷新的就知道了吧。 vue-router就是利用pushState这个属性,在页面前进的时候动态改变history的内容,添加一条记录,接着location跟着改变。同时根据router前往的路由获取对应的js资源文件并挂载到目标dom上实现页面内容的更新,可是页面自己并无刷新。