摘要:新增一條記錄替換當(dāng)前的記錄實(shí)現(xiàn)核心路由綁定標(biāo)簽綁定事件并阻止默認(rèn)事件總結(jié)本文只是簡(jiǎn)述了,路由變化原理,并未去結(jié)合去完成實(shí)現(xiàn)一個(gè)框架路由。
前言
最近學(xué)習(xí)react時(shí),在使用react-router-dom的時(shí)候,對(duì)history原理與路由切換實(shí)現(xiàn)并不了解,經(jīng)過(guò)學(xué)習(xí)后總結(jié)一下吧!
如果你只是使用react 自帶history 那下面這些原理,你可能并不會(huì)用到。但當(dāng)需要使用自己的history 或 使用第三方history 的時(shí)候你就需要了解其原理
在react 中,你要在非組件內(nèi)可以靈活的切換路由,那么你就要使用自定義的history。
// app.jsx import React from "react" import "./App.scss" import { BrowserRouter } from "react-router-dom" import history from "./history" import XtContent from "./layout/content" import Login from "./components/loginModal" function App() { return (模式) } export default App // history.js // 這里使用第三方創(chuàng)建history import { createBrowserHistory } from "history" export default createBrowserHistory() // 在封裝的fetch中使用 import axios from "axios" import history from "@/history"; // 設(shè)置axios 通用 const service = axios.create({ timeout: 5000, headers: { "Content-Type": "application/json;charset=UTF-8" }, withCredentials: true }) // 響應(yīng)攔截 service.interceptors.response.use( response => { //服務(wù)端定義的響應(yīng)code碼為0時(shí)請(qǐng)求成功 if (response.data.code === 200) { //使用Promise.resolve 正常響應(yīng) return Promise.resolve(response.data) } else if (response.data.code === 1002) { //服務(wù)端定義的響應(yīng)code碼為1401時(shí)為未登錄 message.error("登陸失效,請(qǐng)從新登陸!") /////////// 登陸失敗切換登陸頁(yè)面 **history.push("/Login")** ////////// window.localStorage.removeItem("userInfo") return Promise.reject(response.data) //使用Promise.reject 拋出錯(cuò)誤和異常 } else { message.error(response.data.message) return Promise.reject(response.data) } }, error => { if (error && error.response) { let res = {} res.code = error.response.status res.msg = throwErr(error.response.status, error.response) //throwErr 捕捉服務(wù)端的http狀態(tài)碼 定義在utils工具類的方法 message.error(res.msg) return Promise.reject(res) } return Promise.reject(error) } )
在React/Vue的路由時(shí),會(huì)有兩種模式 hash 和 history ,事實(shí)上他們是針對(duì)游覽器的路由模式設(shè)置的。其基本原理實(shí)際就是通關(guān)游覽器提供的監(jiān)聽這兩種模式的變化,從而映射的對(duì)應(yīng)路由的組件render.
基與以上理論簡(jiǎn)單實(shí)現(xiàn)一下路由切換 hashhash 其兼容性好,但一般不采用只是在不支持H5 history 的情況下回退到hash。其在游覽器上的路由形式 http://localhost#/test 與正常路由相比略顯怪異且不美觀(不推薦使用)
核心:監(jiān)聽hash變化觸發(fā)callback // window.addEventListener("hashchange", callback)
// 模擬實(shí)現(xiàn) class Router { constructor() { // 儲(chǔ)存 hash 與 callBack 的映射 this.routes = {}; // 當(dāng)前 路由 this.currentUrl = ""; // 存儲(chǔ)歷史記錄 this.history = []; // 作為指針,默認(rèn)指向 this.history 的末尾,根據(jù)后退前進(jìn)指向 history 中不同的 hash this.currentIndex = this.history.length - 1; this.backIndex = this.history.length - 1 this.refresh = this.refresh.bind(this); this.backOff = this.backOff.bind(this); // 默認(rèn)不是后退操作 this.isBack = false; // 監(jiān)聽load后加載路由 window.addEventListener("load", this.refresh, false); // 監(jiān)聽hash 變化 //window.addEventListener("hashchange", this.refresh, false); } //路由實(shí)例 加添路由映射 route(path, callback) { this.routes[path] = callback || function() {}; } // 根據(jù)由render refresh() { console.log("refresh") this.currentUrl = location.hash.slice(1) || "/"; this.history.push(this.currentUrl); this.currentIndex++; if (!this.isBack) { this.backIndex = this.currentIndex } this.routes[this.currentUrl](); console.log("指針:", this.currentIndex, "history:", this.history); this.isBack = false; } // 后退功能 backOff() { // 后退操作設(shè)置為true console.log(this.currentIndex) console.log(this.backIndex) this.isBack = true; this.backIndex <= 0 ? (this.backIndex = 0) : (this.backIndex = this.backIndex - 1); location.hash = `#${this.history[this.backIndex]}`; } } // 調(diào)用 window.router = new Router() router.route("/", function () { console.log("") changeContent("") }) router.route("/Home1", function () { console.log("Home1") changeContent("Home1") }) router.route("/Home2", function () { console.log("Home2") changeContent("Home2") }) router.route("/Home3", function () { console.log("Home3") changeContent("Home3") })history history API (pushState replaceState)
將游覽器地址上路由切換
修改歷史記錄
不會(huì)刷新頁(yè)面
其路由形式為游覽器標(biāo)準(zhǔn),所以當(dāng)切換到某一路由localhost/test 后再刷新游覽器(F5),游覽器會(huì)向服務(wù)器請(qǐng)求/test下對(duì)應(yīng)的資源,然鵝路由是在前端實(shí)現(xiàn)的服務(wù)器會(huì)找不到資源,在這種模式需要將服務(wù)器接收到的get(contentType = text/html)請(qǐng)求統(tǒng)一返回index.html。下面已node-koa為例
const Koa = require("koa") // 一個(gè)處理前端路由hisrtory模式的node插件 const history = require("koa2-connect-history-api-fallback") const app = new Koa() // 將contentType 為 text/html, application/xhtml+xml 統(tǒng)一返回靜態(tài)資源文件下的index.html app.use(history({ htmlAcceptHeaders: ["text/html", "application/xhtml+xml"] })) * koa2-connect-history-api-fallback 見 https://github.com/davezuko/koa-connect-history-api-fallback
/** * state :歷史記錄相關(guān)聯(lián)的狀態(tài)對(duì)象,當(dāng)popstate事件觸發(fā)時(shí),會(huì)把該對(duì)象傳入回調(diào)函數(shù)。不用可傳null。 * title: 新頁(yè)面的標(biāo)題不用可傳null。 * url: 要切換到的路徑,必須保持與當(dāng)前URL同一個(gè)域。 **/ // 新增一條記錄 history.pushState(state, title, url) // 替換當(dāng)前的記錄 history.replaceState(state, title, url)
#### 實(shí)現(xiàn) #####
* 核心 window.addEventListener("popstate",callBack) class Routers { constructor() { this.routes = {}; this._bindPopState(); } init(path) { history.replaceState({path: path}, null, path); this.routes[path] && this.routes[path](); } route(path, callback) { this.routes[path] = callback || function() {}; } go(path) { history.pushState({path: path}, null, path); this.routes[path] && this.routes[path](); } _bindPopState() { window.addEventListener("popstate", e => { const path = e.state && e.state.path; this.routes[path] && this.routes[path](); }); } } window.Router = new Routers(); Router.init(location.pathname); // 路由綁定 Router.route("/", function() { console.log("/") }); Router.route("/blue", function() { console("blue"); }); Router.route("/green", function() { console("green"); }); // a標(biāo)簽綁定事件、并阻止默認(rèn)事件 a.addEventListener("click", e => { if (e.target.tagName === "A") { e.preventDefault(); Router.go(e.target.getAttribute("href")); } });總結(jié)
本文只是簡(jiǎn)述了,路由變化原理,并未去React/Vue結(jié)合 去完成實(shí)現(xiàn)一個(gè)框架路由。后續(xù)學(xué)習(xí)后會(huì)補(bǔ)上!
參考Hash路由
history路由
作者:易企秀——D_Q_
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/106516.html
摘要:新增一條記錄替換當(dāng)前的記錄實(shí)現(xiàn)核心路由綁定標(biāo)簽綁定事件并阻止默認(rèn)事件總結(jié)本文只是簡(jiǎn)述了,路由變化原理,并未去結(jié)合去完成實(shí)現(xiàn)一個(gè)框架路由。 前言 最近學(xué)習(xí)react時(shí),在使用react-router-dom的時(shí)候,對(duì)history原理與路由切換實(shí)現(xiàn)并不了解,經(jīng)過(guò)學(xué)習(xí)后總結(jié)一下吧! 如果你只是使用react 自帶history 那下面這些原理,你可能并不會(huì)用到。但當(dāng)需要使用自己的hist...
摘要:我們知道是的核心插件,而當(dāng)前項(xiàng)目一般都是單頁(yè)面應(yīng)用,也就是說(shuō)是應(yīng)用在單頁(yè)面應(yīng)用中的。原理是傳統(tǒng)的頁(yè)面應(yīng)用,是用一些超鏈接來(lái)實(shí)現(xiàn)頁(yè)面切換和跳轉(zhuǎn)的其實(shí)剛才單頁(yè)面應(yīng)用跳轉(zhuǎn)原理即實(shí)現(xiàn)原理實(shí)現(xiàn)原理原理核心就是更新視圖但不重新請(qǐng)求頁(yè)面。 近期面試,遇到關(guān)于vue-router實(shí)現(xiàn)原理的問(wèn)題,在查閱了相關(guān)資料后,根據(jù)自己理解,來(lái)記錄下。我們知道vue-router是vue的核心插件,而當(dāng)前vue項(xiàng)目...
摘要:顯示為顯示為顯示為單頁(yè)面應(yīng)用用戶訪問(wèn)軌跡埋點(diǎn)開發(fā)過(guò)單頁(yè)面應(yīng)用的同學(xué),一定比較清楚,單頁(yè)面應(yīng)用的路由切換是無(wú)感知的,不會(huì)重新進(jìn)行請(qǐng)求去獲取頁(yè)面,而是通過(guò)改變頁(yè)面渲染視圖來(lái)實(shí)現(xiàn)。 前言 最近開發(fā)的埋點(diǎn)項(xiàng)目,需要記錄用戶行為軌跡即用戶頁(yè)面訪問(wèn)順序。需要在頁(yè)面跳轉(zhuǎn)的時(shí)候,記錄用戶訪問(wèn)的信息(比如 url ,請(qǐng)求頭部等),非單頁(yè)面應(yīng)用可以給 window 對(duì)象加上一個(gè) beforeunload ...
摘要:而路由則是使用了中新增的事件和事件。總結(jié)這一章主要是介紹了如何使用在中構(gòu)建我們的前端路由。 系列目錄地址 一、基礎(chǔ)知識(shí)概覽 第一章 - 一些基礎(chǔ)概念(posted at 2018-10-31) 第二章 - 常見的指令的使用(posted at 2018-11-01) 第三章 - 事件修飾符的使用(posted at 2018-11-02) 第四章 - 頁(yè)面元素樣式的設(shè)定(posted a...
閱讀 3586·2021-11-04 16:06
閱讀 3585·2021-09-09 11:56
閱讀 848·2021-09-01 11:39
閱讀 900·2019-08-29 15:28
閱讀 2295·2019-08-29 15:18
閱讀 834·2019-08-29 13:26
閱讀 3336·2019-08-29 13:22
閱讀 1048·2019-08-29 12:18