vue-router的两种模式

本文介绍了前端路由的起源,详细讲解了Vue-router的两种路由模式:hash模式和history模式。hash模式利用hash值变化不刷新页面的特性实现路由;而history模式借助HTML5的History API实现页面路由的平滑切换。Vue-router通过mode属性选择不同的实现方式,结合pushState或replaceState处理页面更新。

起源

什么是路由?路由其实就是指向一个特定处理函数的路径(后端:一个路由对应一个controller)
前端Ajax => 局部刷新 => SPA

多页应用单页应用
一个项目中有多个完整的的HTML文件一个项目中只有一个完整的HTML页面(index.html)
可以使用超链接、js实现页面间的跳转可以使用改进后的超链接、js实现模板页面间的切换
传统的页面跳转是同步请求:在服务器生成响应内容时,客户端是一片空白模板页面间的切换属于经典的异步请求:直到下一个模板页面来到,前一个模板页面到来,前一个模板页面才从当前DOM树上删除
页面跳转时,前一个DOM树无用了,需要从浏览器中全部删除,然后等待下一个DOM树的到来index.html到来时,浏览器创建一个DOM树。所有的请求都是xhr,到来时只需要作为一个片段挂载在当前DOM树——浏览器从始至终只有一个DOM树
当网速比较慢时(尤其是移动端应用中时),用户体验极为不好!不会出现一片惨白的情形,浏览体验好。
页面切换时,DOM被完整的删除,不可能有过场动画!页面切换的本质是DIV的轮换,可以很容易实现漂亮的过场动画。

SPA存在的问题: 所有的页面共享一个URL,无法区分,对爬虫、SEO等不友好
=> 前端路由出现:页面切换时改变URL,同时不请求后端刷新html页面

两种路由模式

hash
  1. hash值的改变不会引起页面刷新
  2. window.onhashchange可以监听到路由的变化
  3. 将hash值与页面切换处理函数一一对应
history
  1. HTML5引入了history.pushState() 和 history.replaceState() 方法,分别可以添加和修改历史记录条目,将使浏览器地址栏显示为新地址,但并不会导致浏览器加载页面,甚至不会检查新地址是否存在。使用 history.pushState() 可以改变referrer,它在用户发送 XMLHttpRequest 请求时在HTTP头部使用,改变state后创建的 XMLHttpRequest 对象的referrer都会被改变。因为referrer是标识创建 XMLHttpRequest 对象时 this 所代表的window对象中document的URL。History_APIpushState() 绝对不会触发 hashchange 事件,即使新的URL与旧的URL仅哈希不同也是如此。
  2. 调用history.pushState()或者history.replaceState()不会触发popstate事件. popstate事件只会在浏览器某些行为下触发, 比如点击后退、前进按钮(或者在JavaScript中调用history.back()、history.forward()、history.go()方法)。onpopstate
  3. pushState之后,在popstate触发时绑定页面切换处理函数

Vue-router的路由实现

项目地址:https://github.com/vuejs/vue-router
HTML5History源码实现(/src/index.js)

  push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
    // $flow-disable-line
    if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
      return new Promise((resolve, reject) => {
        this.history.push(location, resolve, reject)
      })
    } else {
      this.history.push(location, onComplete, onAbort)
    }
  }

  replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
    // $flow-disable-line
    if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
      return new Promise((resolve, reject) => {
        this.history.replace(location, resolve, reject)
      })
    } else {
      this.history.replace(location, onComplete, onAbort)
    }
  }

  go (n: number) {
    this.history.go(n)
  }

  back () {
    this.go(-1)
  }

  forward () {
    this.go(1)
  }
  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)
  }

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

router 实例调用的 push 实际是 history 的方法,通过 mode 来确定匹配 history
的实现方案,从代码中我们看到,push 调用了 src/util/push-state.js 中被改写过
的 pushState 的方法,改写过的方法会根据传入的参数 replace?: boolean 来进行
判断调用 pushState 还是 replaceState ,同时做了错误捕获,如果,history 无刷
新修改访问路径失败,则调用 window.location.replace(url) ,有刷新的切换用户访
问地址 ,同理 pushState 也是这样。这里的 transitionTo 方法主要的作用是做视图
的跟新及路由跳转监测,如果 url 没有变化(访问地址切换失败的情况),在
transitionTo 方法内部还会调用一个 ensureURL 方法,来修改 url。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值