国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

從了解Hash和Html5 History 到簡單實現路由

Prasanta / 1400人閱讀

摘要:原因在于將狀態對象保存在用戶的磁盤上,以便在用戶重啟瀏覽器時使用,我們規定了狀態對象在序列化表示后有的大小限制。新不必須為絕對路徑。新必須與當前同源,否則會拋出一個異常。注意絕對不會觸發事件,即使新的與舊的僅哈希不同也是如此。

Hash

hash 屬性是一個可讀可寫的字符串,該字符串是 URL 的錨部分(從 # 號開始的部分),在頁面中的hash有多種功能意義:

錨點
url: http://www.example.com/index.html#jump
dom:  或者 

瀏覽器讀取到hash之后自動滾動到該對應元素所在位置的可視區域內

不附加在請求上

意味著它不管怎么變化都不會影響請求URL,即它只針對瀏覽器的.

瀏覽器: http://www.example.com/index.html#jump
服務器: http://www.example.com/index.html

注意: 有種情況是你會在URL上帶#符號,但是你本意不是作為hash使用的,例如回調地址或者傳參之類,這時候瀏覽器只會當做hash處理,所以需要先轉碼.

// 未轉碼
瀏覽器: http://www.example.com/index.html?test=#123
服務器: http://www.example.com/index.html?test=

// 轉碼
瀏覽器: http://www.example.com/index.html?test=%23123
服務器: http://www.example.com/index.html?test=%23123
改變訪問歷史但不會觸發頁面刷新

這個大家都知道,盡管它不會跳轉也不會刷新,但是你能通過點擊瀏覽器前進后退發現它也會被添加去訪問歷史記錄里.(低版本IE不考慮)

缺點

搜索引擎不友好

難以追蹤用戶行為

思路

當URL的片段標識符更改時,將觸發hashchange事件 (跟在#符號后面的URL部分,包括#符號),然后根據hash值做些路由跳轉處理的操作.具體參數可以訪問location查看

http://www.example.com/index.html#jump

最基本的路由實現方法監聽事件根據location.hash判斷界面



  
    
    
    
    Document
  
  
    
    

具體代碼可以查看hash_demo.html

History

DOM window 對象通過 history 對象提供了對瀏覽器的會話歷史的訪問。它暴露了很多有用的方法和屬性,允許你在用戶瀏覽歷史中向前和向后跳轉

向前和向后跳轉
window.history.back();
window.history.forward();
跳轉到 history 中指定的一個點

你可以用 go() 方法載入到會話歷史中的某一特定頁面, 通過與當前頁面相對位置來標志 (當前頁面的相對位置標志為0).

window.history.go();
添加歷史記錄中的條目

不會立即加載頁面的情況下改變了當前URL地址,往歷史記錄添加一條條目,除非刷新頁面等操作

history.pushState(state, title , URL);

狀態對象

state是一個JavaScript對象,popstate事件的state屬性包含該歷史記錄條目狀態對象的副本。

狀態對象可以是能被序列化的任何東西。原因在于Firefox將狀態對象保存在用戶的磁盤上,以便在用戶重啟瀏覽器時使用,我們規定了狀態對象在序列化表示后有640k的大小限制。如果你給 pushState() 方法傳了一個序列化后大于640k的狀態對象,該方法會拋出異常。如果你需要更大的空間,建議使用 sessionStorage 以及 localStorage.

標題

Firefox 目前忽略這個參數,但未來可能會用到。在此處傳一個空字符串應該可以安全的防范未來這個方法的更改。或者,你可以為跳轉的state傳遞一個短標題。

URL

新的歷史URL記錄。新URL不必須為絕對路徑。如果新URL是相對路徑,那么它將被作為相對于當前URL處理。新URL必須與當前URL同源,否則 pushState() 會拋出一個異常。該參數是可選的,缺省為當前URL。

注意: pushState() 絕對不會觸發 hashchange 事件,即使新的URL與舊的URL僅哈希不同也是如此。

更改歷史記錄中的當前條目

不會立即加載頁面的情況下改變了當前URL地址,并改變歷史記錄的當前條目,除非刷新頁面等操作

history.replaceState(state, title , URL);
popstate 事件

每當活動的歷史記錄項發生變化時, popstate 事件都會被傳遞給window對象。如果當前活動的歷史記錄項是被 pushState 創建的,或者是由 replaceState 改變的,那么 popstate 事件的狀態屬性 state 會包含一個當前歷史記錄狀態對象的拷貝。

獲取當前狀態

頁面加載時,或許會有個非null的狀態對象。這是有可能發生的,舉個例子,假如頁面(通過pushState() 或 replaceState() 方法)設置了狀態對象而后用戶重啟了瀏覽器。那么當頁面重新加載時,頁面會接收一個onload事件,但沒有 popstate 事件。然而,假如你讀取了history.state屬性,你將會得到如同popstate 被觸發時能得到的狀態對象。

你可以讀取當前歷史記錄項的狀態對象state,而不必等待popstate 事件

思路

監聽點擊事件禁止默認跳轉操作,手動利用history實現一套跳轉邏輯,根據location.pathname渲染界面.



  
    
    
    
    Document
  
  
    
    

具體代碼可以查看html5_demo.html
注意,該方法不支持本地運行,只能線上運作或者啟動服務器查看效果

html5_demo.html:26 Uncaught DOMException: Failed to execute "pushState" on "History": A history state object with URL "file:///C:/b" cannot be created in a document with origin "null" and URL "file:///C:/work/project/router_demo/src/html5_demo.html".
    at HTMLAnchorElement. (file:///C:/work/project/router_demo/src/html5_demo.html:26:15)
(anonymous) @ html5_demo.html:26
簡單封裝路由庫 API

基本的路由方法:

router.push(url, onComplete)

router.replace(url, onComplete)

router.go(n)

router.back()

router.stop()



  
    router
  

  
    
  • console.log("push a"))">push a
  • console.log("push b"))">push b
  • console.log("replace c"))">replace c
  • go
  • back
  • stop
初始化
import Router from "../router"

window.router = new Router("view", {
  routes: [
    {
      path: "/a",
      component: "

a

" }, { path: "/b", component: "

b

" }, { path: "/c", component: "

c

" }, { path: "*", redirect: "/index" } ] }, "hash")// 或者"html5"
router類
import HashHstory from "./HashHistory";
import Html5History from "./Html5History";

export default class Router {
  constructor(wrapper, options, mode = "hash") {
    this._wrapper = document.querySelector(`#${wrapper}`)
    if (!this._wrapper) {
      throw new Error(`你需要提供一個容器元素插入`)
    }
    // 是否支持HTML5 History 模式
    this._supportsReplaceState = window.history && typeof window.history.replaceState === "function"
    // 匹配路徑
    this._cache = {}
    // 默認路由
    this._defaultRouter = options.routes[0].path
    this.route(options.routes)
    // 啟用模式
    this._history = (mode !== "hash" && this._supportsReplaceState) ? new Html5History(this, options) : new HashHstory(this, options)
  }

  // 添加路由
  route(routes) {
    routes.forEach(item => this._cache[item.path] = item.component)
  }

  // 原生瀏覽器前進
  go(n = 1) {
    window.history.go(n)
  }

  // 原生瀏覽器后退
  back(n = -1) {
    window.history.go(n)
  }

  // 增加
  push(url, onComplete) {
    this._history.push(url, onComplete)
  }

  // 替換
  replace(url, onComplete) {
    this._history.replace(url, onComplete)
  }

  // 移除事件
  stop() {
    this._history.stop()
  }
}
Hash Class
export default class HashHistory {
  constructor(router, options) {
    this.router = router
    this.onComplete = null
    // 監聽事件
    window.addEventListener("load", this.onChange)
    window.addEventListener("hashchange", this.onChange)
  }

  onChange = () => {
    // 匹配失敗重定向
    if (!location.hash || !this.router._cache[location.hash.slice(1)]) {
      window.location.hash = this.router._defaultRouter
    } else {
      // 渲染視圖
      this.router._wrapper.innerHTML = this.router._cache[location.hash.slice(1)]
      this.onComplete && this.onComplete() && (this.onComplete = null)
    }
  }

  push(url, onComplete) {
    window.location.hash = `${url}`
    onComplete && (this.onComplete = onComplete)
  }

  replace(url, onComplete) {
    // 優雅降級
    if (this.router._supportsReplaceState) {
      window.location.hash = `${url}`
      window.history.replaceState(null, null, `${window.location.origin}#${url}`)
    } else {
      // 需要先看看當前URL是否已經有hash值
      const href = location.href
      const index = href.indexOf("#")
      url = index > 0
        ? `${href.slice(0, index)}#${url}`
        : `${href}#${url}`
      // 域名不變的情況下不會刷新頁面
      window.location.replace(url)
    }

    onComplete && (this.onComplete = onComplete)
  }

  // 移除事件
  stop() {
    window.removeEventListener("load", this.onChange)
    window.removeEventListener("hashchange", this.onChange)
  }
}
HTML5 Class
export default class Html5Hstory {
  constructor(router, options) {
    this.addEvent()
    this.router = router
    this.onComplete = null
    // 監聽事件
    window.addEventListener("popstate", this.onChange)
    window.addEventListener("load", this.onChange)
    window.addEventListener("replaceState", this.onChange);
    window.addEventListener("pushState", this.onChange);
  }

  // pushState/replaceState不會觸發popstate事件,所以我們需要自定義
  addEvent() {
    const listenWrapper = function (type) {
      const _func = history[type];
      return function () {
        const func = _func.apply(this, arguments);
        const e = new Event(type);
        e.arguments = arguments;
        window.dispatchEvent(e);
        return func;
      };
    };
    history.pushState = listenWrapper("pushState");
    history.replaceState = listenWrapper("replaceState");
  }

  onChange() {
    // 匹配失敗重定向
    if (location.pathname === "/" || !this.router._cache[location.pathname]) {
      window.history.pushState(null, "", `${window.location.origin}${this.router._defaultRouter}`);
    } else {
      // 渲染視圖
      this.router._wrapper.innerHTML = this.router._cache[location.pathname]
      this.onComplete && this.onComplete() && (this.onComplete = null)
    }
  }

  push(url, onComplete) {
    window.history.pushState(null, "", `${window.location.origin}${url}`);
    onComplete && (this.onComplete = onComplete)
  }

  replace(url, onComplete) {
    window.history.replaceState(null, null, `${window.location.origin}${url}`)
    onComplete && (this.onComplete = onComplete)
  }

  // 移除事件
  stop() {
    window.removeEventListener("load", this.onChange)
    window.removeEventListener("popstate", this.onChange)
    window.removeEventListener("replaceState", this.onChange)
    window.removeEventListener("pushState", this.onChange)
  }
}

完整代碼可以拷貝router_demo

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/106464.html

相關文章

  • vue-router源碼閱讀學習

    摘要:我們在回到的構造函數中,往下看是模式的選擇,一共這么幾種模式一種和三種。把我們繼續回到中,首先繼承構造函數。表示信息,表示成功后的回調函數,表示失敗的回調函數。是三種的實例對象,然后分情況進行操作,方法就是給賦值穿進去的回調函數。 如同分析vuex源碼我們首先通過一個簡單例子進行了解vue-router是如何使用的,然后在分析在源碼中是如何實現的 示例 下面示例來自于example/b...

    Jason 評論0 收藏0
  • 【Vue.js 牛刀小試】:第十二章 - 使用 Vue Router 實現 Vue 中的前端路由控制

    摘要:而路由則是使用了中新增的事件和事件。總結這一章主要是介紹了如何使用在中構建我們的前端路由。 系列目錄地址 一、基礎知識概覽 第一章 - 一些基礎概念(posted at 2018-10-31) 第二章 - 常見的指令的使用(posted at 2018-11-01) 第三章 - 事件修飾符的使用(posted at 2018-11-02) 第四章 - 頁面元素樣式的設定(posted a...

    cpupro 評論0 收藏0
  • 簡述vue-router實現原理

    摘要:源碼解讀閱讀請關注下代碼注釋打個廣告哪位大佬教我下怎么排版啊,不會弄菜單二級導航撲通是什么首先,你會從源碼里面引入,然后再傳入參數實例化一個路由對象源碼基礎類源碼不選擇模式會默認使用模式非瀏覽器環境默認環境根據參數選擇三種模式的一種根據版 router源碼解讀 閱讀請關注下代碼注釋 打個廣告:哪位大佬教我下sf怎么排版啊,不會弄菜單二級導航(撲通.gif) showImg(https:...

    Cristalven 評論0 收藏0
  • 簡述vue-router實現原理

    摘要:源碼解讀閱讀請關注下代碼注釋打個廣告哪位大佬教我下怎么排版啊,不會弄菜單二級導航撲通是什么首先,你會從源碼里面引入,然后再傳入參數實例化一個路由對象源碼基礎類源碼不選擇模式會默認使用模式非瀏覽器環境默認環境根據參數選擇三種模式的一種根據版 router源碼解讀 閱讀請關注下代碼注釋 打個廣告:哪位大佬教我下sf怎么排版啊,不會弄菜單二級導航(撲通.gif) showImg(https:...

    Ajian 評論0 收藏0

發表評論

0條評論

Prasanta

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<