VueRouter路由实现原理
⼀、概念
  通过改变 URL,在不重新请求页⾯的情况下,更新页⾯视图。
⼆、实现⽅式
  更新视图但不重新请求页⾯,是前端路由原理的核⼼之⼀,⽬前在浏览器环境中这⼀功能的实现主要有2种⽅式:
    1.Hash --- 利⽤ URL 中的hash("#");
    2.利⽤ History interface 在HTML5中新增的⽅法。
  Vue 中,它是通过 mode 这⼀参数控制路由的实现模式:
const router=new VueRouter({
mode:'history',
routes:[...]
})
  创建 VueRouter 的实例对象时,mode 以构造参数的形式传⼊,如下代码:
src/index.js
export default class VueRouter{
mode: string; // 传⼊的字符串参数,指⽰history类别
history: HashHistory | HTML5History | AbstractHistory; // 实际起作⽤的对象属性,必须是以上三个类的枚举
fallback: boolean; // 如浏览器不⽀持,'history'模式需回滚为'hash'模式
constructor (options: RouterOptions = {}) {
let mode = de || 'hash' // 默认为'hash'模式
this.fallback = mode === 'history' && !supportsPushState // 通过supportsPushState判断浏览器是否⽀持'history'模式
if (this.fallback) {
mode = 'hash'
}
if (!inBrowser) {
mode = 'abstract' // 不在浏览器环境下运⾏需强制为'abstract'模式
}
// 根据mode确定history实际的类并实例化
switch (mode) {
case 'history':
this.history = new HTML5History(this, options.base)
break
case 'hash':
this.history = new HashHistory(this, options.base, this.fallback)
break
div只能用innertextcase 'abstract':
this.history = new AbstractHistory(this, options.base)
break
default:
if (v.NODE_ENV !== 'production') {
assert(false, `invalid mode: ${mode}`)
}
}
}
init (app: any /* Vue component instance */) {
const history = this.history
// 根据history的类别执⾏相应的初始化操作和监听
if (history instanceof HTML5History) {foreach用法 w3c
} else if (history instanceof HashHistory) {
const setupHashListener = () => {
history.setupListeners()
}
setupHashListener,
setupHashListener
)
}
history.listen(route => {
this.apps.forEach((app) => {
app._route = route
})
})
}
// VueRouter类暴露的以下⽅法实际是调⽤具体history对象的⽅法
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
this.history.push(location, onComplete, onAbort)
}
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
place(location, onComplete, onAbort)
}
}
源码
html5w3c
  mode 参数:
    1.默认 hash
    2. history。如果浏览器不⽀持 history 新特性,则采⽤ hash
    3. 如果不在浏览器环境下,就采⽤ abstract(Node环境下)
  mode 区别:
    1. mode:"hash"  多了 “#”
localhost:8080/#/login
    2.mode:"history"
localhost:8080/recommend
  HashHistory:
    hash("#") 的作⽤是加载 URL 中指⽰⽹页中的位置。
    # 本⾝以及它后⾯的字符称职位 hash,可通过 window.location.hash 获取    特点:
      1. hash 虽然出现在 url 中,但不会被包括在 http 请求中,它是⽤来指导浏览器动作的,对服务器端完全⽆⽤,因此,改变hash 不会重新加载页⾯。
      2. 可以为 hash 的改变添加监听事件:
      window.addEventListener("hashchange",funcRef,false)
      3. 每⼀次改变 hash(window.localtion.hash),都会在浏览器访问历史中增加⼀个记录。
    利⽤ hash 的以上特点,就可以来实现前端路由"更新视图但不重新请求页⾯"的功能了。
    HashHistory 拥有两个⽅法,⼀个是 push,⼀个是 replace
    两个⽅法:HashHistory.push() 和 place()
    HashHistory.push()  将新路由添加到浏览器访问历史的栈顶
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
pushHash(route.fullPath)
onComplete && onComplete(route)
}, onAbort)
}
function pushHash (path) {
window.location.hash = path
}
HashHisttory.push()
    从设置路由改变到视图更新的流程: 
$router.push() --> HashHistory.push() --> ansitionTo() --> History.updateRoute() --> {app._route = route} --> vm.render()
    解析:
1 $router.push() //调⽤⽅法
2 HashHistory.push() //根据hash模式调⽤,设置hash并添加到浏览器历史记录(添加到栈顶)(window.location.hash= XXX)
ansitionTo() //监测更新,更新则调⽤History.updateRoute()
4 History.updateRoute() //更新路由
5 {app._route= route} //替换当前app路由
der() //更新视图
    transitionTo() ⽅法是⽗类中定义的是⽤来处理路由变化中的基础逻辑的,push() ⽅法最主要的是对 window 的 hash 进⾏了直接赋值:
swift教程听说跟lebus学ios开发window.location.hash=route.fullPath
    hash 的改变会⾃动添加到浏览器的访问历史记录中。
    那么视图的更新是怎么实现的呢,我们来看看⽗类 History 中的 transitionTo() ⽅法:
transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) {position和location的区别
const route = uter.match(location, this.current)
this.updateRoute(route)
...
})
}
updateRoute (route: Route) {
this.cb && this.cb(route)
}
listen (cb: Function) {
this.cb = cb
}
    可以看到,当路由变化时,调⽤了Hitory中的this.cb⽅法,⽽this.cb⽅法是通过History.listen(cb)进⾏设置的,回到VueRouter类定义中,到了在init()中对其进⾏了设置:
init (app: any /* Vue component instance */) {
this.apps.push(app)
history.listen(route => {
this.apps.forEach((app) => {
app._route = route
})
})
}
    place()
      replace()⽅法与push()⽅法不同之处在于,它并不是将新路由添加到浏览器访问历史的栈顶,⽽是替换掉当前的路由
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
replaceHash(route.fullPath)
onComplete && onComplete(route)
}, onAbort)
}
function replaceHash (path) {
const i = window.location.href.indexOf('#')
place(
window.location.href.slice(0, i >= 0 ? i : 0) + '#' + path
)
京东秒杀倒计时代码}
  HTML5History
    History interface 是浏览器历史记录栈提供的接⼝,通过back()、forward()、go()等⽅法,我们可以读取浏览器历史记录栈的信息,进⾏各种跳转操作。
    从 HTML5开始,History interface 提供了2个新的⽅法:pushState()、replaceState() 使得我们可以对浏览器历史记录栈进⾏修改:
  window.history.pushState(stateObject,title,url)
  window.history,replaceState(stateObject,title,url)
    stateObject:当浏览器跳转到新的状态时,将触发 Popstate 事件,该事件将携带这个 stateObject 参数的副本
    title:所添加记录的标题
    url:所添加记录的 url
    这2个⽅法有个共同的特点:当调⽤他们修改浏览器历史栈后,虽然当前url改变了,但浏览器不会⽴即发送请求该url,这就为单页应⽤前端路由,更新视图但不重新请求页⾯提供了基础
    1.push
      与hash模式类似,只是将window.hash改为history.pushState
    2.replace
      与hash模式类似,只是将place改为placeState
    3.监听地址变化
      在HTML5History的构造函数中监听popState(popstate)
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
const { current: fromRoute } = this
pushState(cleanPath(this.base + route.fullPath))
uter, route, fromRoute, false)
onComplete && onComplete(route)
}, onAbort)
}
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
const { current: fromRoute } = this
replaceState(cleanPath(this.base + route.fullPath))
uter, route, fromRoute, false)
onComplete && onComplete(route)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。