摘要:前端路由庫的作用是改變地址欄,支持瀏覽器前進后退,并同步路由對應(yīng)的視圖,這里以及其依賴的庫說一下路由機制原文地址前提首先簡單介紹一下前端路由機制所依賴的事件及對應(yīng)的事件對于支持新增方法的瀏覽器,可以通過設(shè)置來在瀏覽器棧中新增一條記錄設(shè)置時
前端路由庫的作用是改變地址欄,支持瀏覽器前進、后退,并同步路由對應(yīng)的視圖,這里以react-router及其依賴的history庫說一下路由機制
原文地址
前提首先簡單介紹一下前端路由機制所依賴的pushState、popstate事件、hash及對應(yīng)的hashChange事件
pushState,popstate
對于支持html5 新增pushState、replaceState方法的瀏覽器,可以通過設(shè)置pushState來在瀏覽器history棧中新增一條記錄
設(shè)置pushState(),replaceState()時并不會觸發(fā)popstate事件,popstate事件只在點擊瀏覽器前進、后退按鈕或調(diào)用history.back()、history.forward()等時觸發(fā)
pushState()方法第一個參數(shù)可以指定一個state對象,并通過history.state或popstate事件回調(diào)中event對象獲取
history.pushState(state,title,path) console.log(history.state) window.addEventListener("popstate",(e)=>{ console.log(e.state) })
location.hash hashChange
對于不支持pushState方法的瀏覽器,可以通過改變location.hash和借助hashChange事件來實現(xiàn)路由功能
window.addEventListener("hashchange",e=>{ }) location.hash="test"
對比
通過設(shè)置history.pushState(state,title,path),可以給對應(yīng)路由設(shè)置一個state,這就給路由之間的數(shù)據(jù)傳遞提供了一種新途徑,并且,state對象是保存在本地的,刷新頁面依然存在,但通過hash方式實現(xiàn)的路由就沒法使用,react-router v4版本也去除了
history庫提供了三種不同的方法來創(chuàng)建history對象,這里的history對象是對瀏覽器內(nèi)置window.history方法的擴展,擴展了push,go,goBack,goForward等方法,并加入了location、listen字段,并對非瀏覽器環(huán)境實現(xiàn)polyfill
createBrowserHistory() createHashHistory() createMemoryHistory()react-router的路由實現(xiàn)(BrowserRouter和createBrowserHistory)
react-router路由實現(xiàn)大體過程
調(diào)用history.push跳轉(zhuǎn)路由時,內(nèi)部執(zhí)行window.history.pushState在瀏覽器history棧中新增一條記錄,改變url,執(zhí)行
createBrowserHistory中注冊popstate事件,用戶點擊瀏覽器前進、回退時,在popstate事件中獲取當(dāng)前的event.state,重新組裝一個location,執(zhí)行
history庫對外暴露createBrowserHistory方法,react-router中實例化createBrowserHistory方法對象,在
分別來看
history.push在react中,我們可以調(diào)用history.push(path,state)來跳轉(zhuǎn)路由,實際執(zhí)行的就是createBrowserHistory中的push方法
在這個方法中主要做三件事
根據(jù)傳遞的path,state參數(shù)創(chuàng)建一個location,不同于window.location,這里的location只有這些屬性
location= { path: search: hash: state: key }; const location = createLocation(path, state, createKey(), history.location);
這個location會在
執(zhí)行g(shù)lobalHistory.pushState({ key, state }, null, href);
執(zhí)行Router中注冊的listener
const action = "PUSH" setState({ action, location }); const setState = nextState => { Object.assign(history, nextState); history.length = globalHistory.length; transitionManager.notifyListeners(history.location, history.action); };history中對popstate事件的注冊
popstate事件觸發(fā)時,可以得到event.state,createBrowserHistory中會根據(jù)這個state和當(dāng)前window.location重新生成一個location對象,執(zhí)行Router組件注冊的listener,同步UI
const setState = nextState => { Object.assign(history, nextState); history.length = globalHistory.length; transitionManager.notifyListeners(history.location, history.action); }; const handlePop = location => { const action = "POP"; setState({action,location) }
BrowserRouter組件中會實例化一個createBrowserHistory對象,傳遞給Router組件
class BrowserRouter extends React.Component{ history = createHistory(this.props); render() { return; } }
在Router組件中要注冊history.listen()的一個監(jiān)聽函數(shù),并且保存一份子組件(Route)使用的數(shù)據(jù)
getChildContext() { return { router: { ...this.context.router, history: this.props.history, route: { location: this.props.history.location, //history中的location match: this.state.match } } }; } componentWillMount{ this.unlisten = history.listen(() => { this.setState({ match: this.computeMatch(history.location.pathname) }); }); }
當(dāng)調(diào)用history.push或觸發(fā)popstate事件時,這里注冊的listener都會被createBrowserHistory執(zhí)行,觸發(fā)setState,然后Router的子組件中匹配的
在Route中有一個match狀態(tài),在父組件props發(fā)生變化時會重新計算
state = { match: this.computeMatch(this.props, this.context.router) }; componentWillReceiveProps(nextProps, nextContext) { this.setState({ match: this.computeMatch(nextProps, nextContext.router) }); } //computeMatch主要工作就是匹配當(dāng)前組件上指定的path和當(dāng)前瀏覽器的路徑是否一致,一致就渲染組件 render() { if (component) return match ? React.createElement(component, props) : null; if (render) return match ? render(props) : null; }總結(jié)
總結(jié)一下,react-router的路由機制就是
借助history庫,history中實現(xiàn)了push,go,goBack等方法,注冊了popstate事件,當(dāng)路由跳轉(zhuǎn)時,使用瀏覽器內(nèi)置的history api 操作 history棧
history庫對外暴露的history對象提供了listen方法,
當(dāng)調(diào)用hsitory.push或popstate事件觸發(fā)時,執(zhí)行l(wèi)istener
雖然本文以react-router來介紹路由機制,但主流路由庫實現(xiàn)原理都差不多,借助pushState或hash來更新url,在對應(yīng)的事件處理函數(shù)中來做視圖的同步
參考
createBrowserHistory.js
locationUtil.js
BrowserRouter.js
Router.js
Route.js
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/107215.html
摘要:回調(diào)函數(shù)將在更新時觸發(fā),回調(diào)中的起到了新的的作用。注冊回調(diào)在中使用注冊的回調(diào)函數(shù),最終放在模塊的回調(diào)函數(shù)數(shù)組中。 原文地址:https://github.com/joeyguo/blog/issues/2 在單頁應(yīng)用上,前端路由并不陌生。很多前端框架也會有獨立開發(fā)或推薦配套使用的路由系統(tǒng)。那么,當(dāng)我們在談前端路由的時候,還可以談些什么?本文將簡要分析并實現(xiàn)一個的前端路由,并對 reac...
摘要:如何在新的技術(shù)背景下讓前端數(shù)據(jù)采集工作更加完善高效,是本文討論的重點。具體來說,我們對前端的數(shù)據(jù)采集具體主要分為路由切換性能資源錯誤日志上報路由切換等前端技術(shù)的快速發(fā)展使單頁面應(yīng)用盛行。 隨著業(yè)務(wù)的快速發(fā)展,我們對生產(chǎn)環(huán)境下的問題感知能力越來越關(guān)注。作為距離用戶最近的一層,前端的表現(xiàn)是否可靠、穩(wěn)定、好用,很大程度上決定著用戶對整個產(chǎn)品的體驗和感受。因此,對于前端的監(jiān)控不容忽視。 搭建一...
摘要:單頁面應(yīng)用的出現(xiàn)依然存在著爭議性,我們該如何看待他的兩面性呢接下來小生給大家總結(jié)一下他的優(yōu)缺點。單頁面應(yīng)用的優(yōu)勢無刷新體驗沒有了令人詬病的頁面頻繁刷新,同時節(jié)約瀏覽器資源,路由響應(yīng)比較及時,提升了用戶的體驗。 前端猿一天不學(xué)習(xí)就沒飯吃了,后端猿三天不學(xué)習(xí)仍舊有白米飯擺于桌前。IT行業(yè)的快速發(fā)展一直在推動著前端技術(shù)棧在不斷地更新?lián)Q代,前端的發(fā)展成了互聯(lián)網(wǎng)時代的一個縮影。而單頁面應(yīng)用的發(fā)展...
摘要:單頁面應(yīng)用的出現(xiàn)依然存在著爭議性,我們該如何看待他的兩面性呢接下來小生給大家總結(jié)一下他的優(yōu)缺點。單頁面應(yīng)用的優(yōu)勢無刷新體驗沒有了令人詬病的頁面頻繁刷新,同時節(jié)約瀏覽器資源,路由響應(yīng)比較及時,提升了用戶的體驗。 前端猿一天不學(xué)習(xí)就沒飯吃了,后端猿三天不學(xué)習(xí)仍舊有白米飯擺于桌前。IT行業(yè)的快速發(fā)展一直在推動著前端技術(shù)棧在不斷地更新?lián)Q代,前端的發(fā)展成了互聯(lián)網(wǎng)時代的一個縮影。而單頁面應(yīng)用的發(fā)展...
閱讀 2181·2021-11-24 10:26
閱讀 2792·2021-11-23 09:51
閱讀 2907·2021-10-08 10:05
閱讀 1683·2021-09-22 15:18
閱讀 1619·2019-08-29 18:45
閱讀 2143·2019-08-29 18:40
閱讀 3332·2019-08-29 16:16
閱讀 2849·2019-08-29 14:21