1. 程式人生 > >前端路由原理及vue-router介紹

前端路由原理及vue-router介紹

hash spa pst eth sam tar pop xtend 發送

前端路由原理本質就是監聽 URL 的變化,然後匹配路由規則,顯示相應的頁面,並且無須刷新。目前單頁面使用的路由就只有兩種實現方式

hash

history

www.test.com/##/ 就是 Hash URL,當 ## 後面的哈希值發生變化時,不會向服務器請求數據,可以通過 hashchange 事件來監聽到 URL 的變化,從而進行跳轉頁面。

技術分享圖片

vue-router hash實現源碼(完整源碼訪問https://github.com/vuejs/vue-router/blob/dev/src/history/hash.js#L22-L54):

**
 * 添加 url hash 變化的監聽器
 */
setupListeners () {
  const router 
= this.router /** * 每當 hash 變化時就解析路徑 * 匹配路由 */ window.addEventListener(‘hashchange‘, () => { const current = this.current /** * transitionTo: * 匹配路由 * 並通過路由配置,把新的頁面 render 到 ui-view 的節點 */ this.transitionTo(getHash(), route => { replaceHash(route.fullPath) }) }) }

檢測到 hash 的變化後,就可以通過替換 DOM 的方式來實現頁面的更換。

History 模式是 HTML5 新推出的功能,比之 Hash URL 更加美觀

兩個 API ,pushState和replaceState可以改變 url 地址且不會發送請求,還有onpopState事件。但因為沒有 # 號,所以當用戶刷新頁面之類的操作時,瀏覽器還是會給服務器發送請求。為了避免出現這種情況,所以這個實現需要服務器的支持,需要把所有路由都重定向到根頁面。具體可以訪問官網:https://router.vuejs.org/zh/guide/essentials/history-mode.html

技術分享圖片

vue-router history實現源碼(完整源碼訪問https://github.com/vuejs/vue-router/blob/dev/src/history/html5.js)

export class HTML5History extends History {
  constructor (router, base) {
    super(router, base)
    /**
     * 原理還是跟 hash 實現一樣
     * 通過監聽 popstate 事件
     * 匹配路由,然後更新頁面 DOM
     */
    window.addEventListener(‘popstate‘, e => {
      const current = this.current

      // Avoiding first `popstate` event dispatched in some browsers but first
      // history route not updated since async guard at the same time.
      const location = getLocation(this.base)
      if (this.current === START && location === initLocation) {
        return
      }

      this.transitionTo(location, route => {
        if (supportsScroll) {
          handleScroll(router, route, current, true)
        }
      })
    })
  }

  go (n) {
    window.history.go(n)
  }

  push (location, onComplete, onAbort) {
    const { current: fromRoute } = this
    this.transitionTo(location, route => {
      // 使用 pushState 更新 url,不會導致瀏覽器發送請求,從而不會刷新頁面
      pushState(cleanPath(this.base + route.fullPath))
      onComplete && onComplete(route)
    }, onAbort)
  }

  replace (location, onComplete, onAbort) {
    const { current: fromRoute } = this
    this.transitionTo(location, route => {
      // replaceState 跟 pushState 的區別在於,不會記錄到歷史棧
      replaceState(cleanPath(this.base + route.fullPath))
      onComplete && onComplete(route)
    }, onAbort)
  }
}

前端路由原理及vue-router介紹