亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

從了解Hash和Html5 History 到簡單實(shí)現(xiàn)路由

Prasanta / 1460人閱讀

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

Hash

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

錨點(diǎn)
url: http://www.example.com/index.html#jump
dom:  或者 

瀏覽器讀取到hash之后自動(dòng)滾動(dòng)到該對(duì)應(yīng)元素所在位置的可視區(qū)域內(nèi)

不附加在請求上

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

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

注意: 有種情況是你會(huì)在URL上帶#符號(hào),但是你本意不是作為hash使用的,例如回調(diào)地址或者傳參之類,這時(shí)候?yàn)g覽器只會(huì)當(dāng)做hash處理,所以需要先轉(zhuǎn)碼.

// 未轉(zhuǎn)碼
瀏覽器: http://www.example.com/index.html?test=#123
服務(wù)器: http://www.example.com/index.html?test=

// 轉(zhuǎn)碼
瀏覽器: http://www.example.com/index.html?test=%23123
服務(wù)器: http://www.example.com/index.html?test=%23123
改變訪問歷史但不會(huì)觸發(fā)頁面刷新

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

缺點(diǎn)

搜索引擎不友好

難以追蹤用戶行為

思路

當(dāng)URL的片段標(biāo)識(shí)符更改時(shí),將觸發(fā)hashchange事件 (跟在#符號(hào)后面的URL部分,包括#符號(hào)),然后根據(jù)hash值做些路由跳轉(zhuǎn)處理的操作.具體參數(shù)可以訪問location查看

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

最基本的路由實(shí)現(xiàn)方法監(jiān)聽事件根據(jù)location.hash判斷界面



  
    
    
    
    Document
  
  
    
    

具體代碼可以查看hash_demo.html

History

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

向前和向后跳轉(zhuǎn)
window.history.back();
window.history.forward();
跳轉(zhuǎn)到 history 中指定的一個(gè)點(diǎn)

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

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

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

history.pushState(state, title , URL);

狀態(tài)對(duì)象

state是一個(gè)JavaScript對(duì)象,popstate事件的state屬性包含該歷史記錄條目狀態(tài)對(duì)象的副本。

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

標(biāo)題

Firefox 目前忽略這個(gè)參數(shù),但未來可能會(huì)用到。在此處傳一個(gè)空字符串應(yīng)該可以安全的防范未來這個(gè)方法的更改?;蛘?,你可以為跳轉(zhuǎn)的state傳遞一個(gè)短標(biāo)題。

URL

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

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

更改歷史記錄中的當(dāng)前條目

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

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

每當(dāng)活動(dòng)的歷史記錄項(xiàng)發(fā)生變化時(shí), popstate 事件都會(huì)被傳遞給window對(duì)象。如果當(dāng)前活動(dòng)的歷史記錄項(xiàng)是被 pushState 創(chuàng)建的,或者是由 replaceState 改變的,那么 popstate 事件的狀態(tài)屬性 state 會(huì)包含一個(gè)當(dāng)前歷史記錄狀態(tài)對(duì)象的拷貝。

獲取當(dāng)前狀態(tài)

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

你可以讀取當(dāng)前歷史記錄項(xiàng)的狀態(tài)對(duì)象state,而不必等待popstate 事件

思路

監(jiān)聽點(diǎn)擊事件禁止默認(rèn)跳轉(zhuǎn)操作,手動(dòng)利用history實(shí)現(xiàn)一套跳轉(zhuǎn)邏輯,根據(jù)location.pathname渲染界面.



  
    
    
    
    Document
  
  
    
    

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

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(`你需要提供一個(gè)容器元素插入`)
    }
    // 是否支持HTML5 History 模式
    this._supportsReplaceState = window.history && typeof window.history.replaceState === "function"
    // 匹配路徑
    this._cache = {}
    // 默認(rèn)路由
    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)
  }

  // 原生瀏覽器前進(jìn)
  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
    // 監(jiān)聽事件
    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) {
    // 優(yōu)雅降級(jí)
    if (this.router._supportsReplaceState) {
      window.location.hash = `${url}`
      window.history.replaceState(null, null, `${window.location.origin}#${url}`)
    } else {
      // 需要先看看當(dāng)前URL是否已經(jīng)有hash值
      const href = location.href
      const index = href.indexOf("#")
      url = index > 0
        ? `${href.slice(0, index)}#${url}`
        : `${href}#${url}`
      // 域名不變的情況下不會(huì)刷新頁面
      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
    // 監(jiān)聽事件
    window.addEventListener("popstate", this.onChange)
    window.addEventListener("load", this.onChange)
    window.addEventListener("replaceState", this.onChange);
    window.addEventListener("pushState", this.onChange);
  }

  // pushState/replaceState不會(huì)觸發(fā)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

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/106464.html

相關(guān)文章

  • vue-router源碼閱讀學(xué)習(xí)

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

    Jason 評(píng)論0 收藏0
  • 【Vue.js 牛刀小試】:第十二章 - 使用 Vue Router 實(shí)現(xiàn) Vue 中的前端路由控制

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

    cpupro 評(píng)論0 收藏0
  • 簡述vue-router實(shí)現(xiàn)原理

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

    Cristalven 評(píng)論0 收藏0
  • 簡述vue-router實(shí)現(xiàn)原理

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

    Ajian 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<