摘要:原因在于將狀態(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
HistoryDOM 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.簡單封裝路由庫 API(file:///C:/work/project/router_demo/src/html5_demo.html:26:15) (anonymous) @ html5_demo.html:26 基本的路由方法:
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: "router類a
" }, { path: "/b", component: "b
" }, { path: "/c", component: "c
" }, { path: "*", redirect: "/index" } ] }, "hash")// 或者"html5"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 Classexport 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 Classexport 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
摘要:我們在回到的構(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...
摘要:而路由則是使用了中新增的事件和事件??偨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...
摘要:源碼解讀閱讀請關(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:...
摘要:源碼解讀閱讀請關(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:...
閱讀 3320·2021-09-22 15:58
閱讀 1783·2019-08-30 14:17
閱讀 1777·2019-08-28 18:05
閱讀 1569·2019-08-26 13:33
閱讀 738·2019-08-26 12:20
閱讀 667·2019-08-26 12:18
閱讀 3258·2019-08-26 11:59
閱讀 1461·2019-08-26 10:36