vue-router原理及实现

原文地址:https://zhuanlan.zhihu.com/p/27588422

1、功能实现主要有两种方式:
利用url中的hash值
利用history interface在h5中新增的方法
共同点:更新视图但不重新请求页面

HashHistory
hash虽然出现在URL中,但不会被包括在HTTP请求中。它是用来指导浏览器动作的,对服务器端完全无用,因此,改变hash不会重新加载页面

hashhistory中的push方法:
push()方法最主要的是对window的hash进行了直接赋值:
window.location.hash = route.fullPath

push (location: RawLocation, onComplete?: Function, onAbort?:		 Function) {
  this.transitionTo(location, route => {
     pushHash(route.fullPath)
     onComplete && onComplete(route)
  }, onAbort)
 }
function pushHash (path) {
    window.location.hash = path
 }
transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) {
     const route = this.router.match(location, this.current)
     this.confirmTransition(route, () => {
          this.updateRoute(route)
           ...
 })
}
updateRoute (route: Route) {
  this.cb && this.cb(route)
}
listen (cb: Function) {
  this.cb = cb 
}

HashHistory.replace()
replace()方法与push()方法不同之处在于,它并不是将新路由添加到浏览器访问历史的栈顶,而是替换掉当前的路由:

replace (location: RawLocation, onComplete?: Function, onAbort?: 	   Function) {
    this.transitionTo(location, route => {
       replaceHash(route.fullPath)
       onComplete && onComplete(route)
    }, onAbort)
}
function replaceHash (path) {
   const i = window.location.href.indexOf('#')
   window.location.replace(
      window.location.href.slice(0, i >= 0 ? i : 0) + '#' + path
 )
}

监听地址栏:

setupListeners () {
 window.addEventListener('hashchange', () => {
	 if (!ensureSlash()) {
          return
      }
      this.transitionTo(getHash(), route => {
          replaceHash(route.fullPath)
      })
 })
}

HTML5History:
从HTML5开始,History interface提供了两个新的方法:pushState(), replaceState()使得我们可以对浏览器历史记录栈进行修改:

window.history.pushState(stateObject, title, URL)
window.history.replaceState(stateObject, title, URL)

代码结构以及更新视图的逻辑与hash模式基本类似,只不过将对window.location.hash直接进行赋值window.location.replace()改为了调用history.pushState()和history.replaceState()方法。参看代码:

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)
}
// src/util/push-state.js
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)
 }
}
export function replaceState (url?: string) {
    pushState(url, true)
}

在HTML5History中添加对修改浏览器地址栏URL的监听是直接在构造函数中执行的:

constructor (router: Router, base: ?string) {
   window.addEventListener('popstate', e => {
	const current = this.current
	this.transitionTo(getLocation(this.base), route => {
  		if (expectScroll) {
   		 handleScroll(router, route, current, true)
  		}
  	})
   })
}

HTML5History用到了HTML5的新特特性,是需要特定浏览器版本的支持的

// src/util/push-state.js
export const supportsPushState = inBrowser && (function () {
 const ua = window.navigator.userAgent
 if ((ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 	4.0') !== -1) &&
	ua.indexOf('Mobile Safari') !== -1 &&
    ua.indexOf('Chrome') === -1 &&
    ua.indexOf('Windows Phone') === -1) {
       return false
 }
 return window.history && 'pushState' in window.history
})()

vue-router还为非浏览器环境准备了一个abstract模式,其原理为用一个数组stack模拟出浏览器历史记录栈的功能

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值