如何制作自己的原生JavaScript路由
前言
當(dāng)你想到路由時(shí),通常會(huì)想到類(lèi)似react之類(lèi)的庫(kù)。但實(shí)際上,這些庫(kù)和框架仍然使用vanillaJavaScript。那么該怎么實(shí)現(xiàn)呢?
我希望這個(gè)“JavaScript路由教程”能夠幫你了解如何用原生js寫(xiě)出自己的路由。
簡(jiǎn)介
我遇到了很多出于各種原因想要自己創(chuàng)建路由的人。既然你看到本文,那意味著你可能也是其中的一個(gè)!
最重要的是,使用vanillajsrouter可以減少你對(duì)框架的依賴(lài)。
只要你了解實(shí)現(xiàn)它所涉及的所有部分,就可以相對(duì)容易的在原生 JavaScript 中創(chuàng)建自己的路由。
以下是制作自己的JS router時(shí)要了解的關(guān)鍵事項(xiàng):
1.原生 JS 路由的關(guān)鍵是location.pathname屬性。
2.偵聽(tīng) “popstate”事件以響應(yīng).pathname的更改。每當(dāng)在瀏覽器的地址欄中輸入新的 URL,但我們不想刷新頁(yè)面時(shí),就會(huì)發(fā)生這種情況,我們只是想通過(guò)加載新內(nèi)容來(lái)刷新視圖。
3.你可以選擇將路由存儲(chǔ)在routes[]數(shù)組中。
4.必須用JavaScript 正則表達(dá)式(RegEx)才能解析 URL。
5.如果希望將路由集成到本機(jī)瀏覽器體系結(jié)構(gòu)中,那么對(duì)history和history.pushState(JavaScript 的 History API)的基本了解至關(guān)重要。
首先,我們將處理 History API。
JavaScript 的 History API
我看過(guò)很多沒(méi)有提到 JavaScript History API 的vanilla JS router教程。太糟糕了,因?yàn)閱螕魹g覽器的“后退”和“前進(jìn)”按鈕與瀏覽歷史記錄中的 URL 導(dǎo)航有關(guān)。如果沒(méi)有 History API,就無(wú)法談?wù)撀酚伞?/p>
1.history.back()與history.go(-1)相同,或者當(dāng)用戶(hù)在瀏覽器中單擊Back按鈕時(shí)。你可以用任何一種方法達(dá)到相同的效果。
2.當(dāng)用戶(hù)按下瀏覽器的Forward按鈕時(shí),將執(zhí)行history.forward(),它等效于history.go(1)”。
3.go()與.back()和forward()方法相似,不同之處在于你可以指定瀏覽器歷史記錄棧中要前進(jìn)或后退的步數(shù)。 。
4.pushState()會(huì)將新?tīng)顟B(tài)推送到 History API。
5..length屬性是會(huì)話(huà)歷史記錄中的元素?cái)?shù)。
6..state屬性用于查找狀態(tài),而無(wú)需偵聽(tīng)“ popstate”事件。
實(shí)現(xiàn)自己的原生JS路由
基于 History API 的 Vanilla JS 路由設(shè)置
先讓我們仔細(xì)研究構(gòu)建 URL 切換器所需的最少代碼(而無(wú)需刷新頁(yè)面),然后我會(huì)向你展示其的工作方式的 GIF 動(dòng)圖。
<html>
<head>
<title>Hello</title>
<script type = "module">
function select_tab(id) {
// remove selected class from all buttons
document.querySelectorAll(".route").forEach(item => item.classList.remove('selected'));
// select clicked element (visually)
document.querySelectorAll("#" + id).forEach(item => item.classList.add('selected'));
}
function load_content(id) {
// Update text "Content loading for {id}..."
// Of course, here you would do you content loading magic
// Perhaps run Fetch API to update resources
document.querySelector("#content").innerHTML = 'Content loading for /' + id + '...';
}
function push(event) {
// Get id attribute of the box or button or link clicked
let id = event.target.id;
// Visually select the clicked button/tab/box
select_tab(id);
// Update Title in Window's Tab
document.title = id;
// Load content for this tab/page
loadContent(id);
// Finally push state change to the address bar
window.history.pushState({id}, `${id}`, `/page/${id}`);
}
window.onload = event => {
// Add history push() event when boxes are clicked
window["home"].addEventListener("click", event => push(event))
window["about"].addEventListener("click", event => push(event))
window["gallery"].addEventListener("click", event => push(event))
window["contact"].addEventListener("click", event => push(event))
window["help"].addEventListener("click", event => push(event))
}
// Listen for PopStateEvent (Back or Forward buttons are clicked)
window.addEventListener("popstate", event => {
// Grab the history state id
let stateId = event.state.id;
// Show clicked id in console (just for fun)
console.log("stateId = ", stateId);
// Visually select the clicked button/tab/box
select_tab(stateId);
// Load content for this tab/page
loadContent(id);
});
</script>
<style>
* { /* global font */
font-family: Verdana;
font-size: 18px;
}
#root { display: flex; flex-direction: row; }
#content { display: flex;
display: block;
width: 800px;
height: 250px;
/* vertically centered text */
line-height: 250px;
border: 2px solid #555;
margin: 32px;
text-align: center;
}
.route {
cursor: pointer;
justify-content: center;
width: 150px;
height: 50px;
/* vertically centered text */
line-height: 50px;
position: relative;
border: 2px solid #555;
background: white;
text-align: center;
margin: 16px;
}
.route.selected { background: yellow; }
</style>
</head>
<body>
<section id = "root">
<section class = "route" id = "home">/home</section>
<section class = "route" id = "about">/about</section>
<section class = "route" id = "gallery">/gallery</section>
<section class = "route" id = "contact">/contact</section>
<section class = "route" id = "help">/help</section>
</section>
<main id = "content">Content loading...</main>
</body>
</html>
核心是對(duì)的window.history.pushState({id}, ${id}, /page/${id});調(diào)用;
第一個(gè)參數(shù)是狀態(tài)的唯一 ID,第二個(gè)是“標(biāo)簽標(biāo)題”文本,第三個(gè)參數(shù)是你希望地址欄中要現(xiàn)實(shí)的路徑。這就是使瀏覽器無(wú)需重新加載頁(yè)面即可更改 URL 的原因。
結(jié)果?,F(xiàn)在,每次我們單擊按鈕時(shí),URL實(shí)際上都會(huì)在瀏覽器的地址欄中更改。內(nèi)容框也會(huì)更新。
我們的原生 JS 路由開(kāi)始運(yùn)行了。請(qǐng)注意,每次單擊按鈕時(shí),history.pushState 被觸發(fā)。我們只需將存儲(chǔ)在元素的 id 屬性中的 clicked 元素的 id 傳遞給它即可:home,about,gallery等。它們應(yīng)與你要導(dǎo)航到的實(shí)際頁(yè)面一致。當(dāng)然這不是存儲(chǔ)頁(yè)面名稱(chēng)的唯一方法,例如可以用 array [] 或其他任何方式。這就是本例中的操作方式。
當(dāng)然我們還需要從服務(wù)器加載有關(guān)該位置的布局和資源的內(nèi)容。這取決于你的程序??梢允侨魏螙|西。
使“后退”和“前進(jìn)”按鈕起作用
通過(guò)使用history.pushState,你將自動(dòng)使Back和Forward按鈕導(dǎo)航到上一個(gè)或下一個(gè)狀態(tài)。這樣做會(huì)產(chǎn)生popstate事件。這是你必須再次更新視圖的部分。 (第一次是我們單擊按鈕時(shí)。)
但是由于該事件帶有單擊的id,因此單擊Back或Forward時(shí)很容易刷新視圖并重新加載內(nèi)容。
我們?cè)谶@里沒(méi)有使用react或vue,因此在我的源代碼中l(wèi)oad_content將負(fù)責(zé)直接在 DOM 中更新視圖。此區(qū)域可能填充了你的 API 加載的某些內(nèi)容。由于這只是“前端”示例,因此我無(wú)法向你展示太多內(nèi)容。但這就是它在客戶(hù)端上的工作方式。
初始化服務(wù)器端的路由負(fù)載
將它們放在一起還需要再執(zhí)行一個(gè)步驟。在我的例子中,只用了router.html。當(dāng)你第一次在 PWA 中加載此路由時(shí),必須確保如果直接在地址欄中輸入/page/home時(shí),它可以工作。
到目前為止,我們僅從前端更改了路由器地址。假定每次你導(dǎo)航到出現(xiàn)在路由按鈕上的 URL 時(shí),實(shí)際上都會(huì)從服務(wù)器單獨(dú)加載該 URL。
因此你有責(zé)任確保/page/about將路由器和頁(yè)面的加載到應(yīng)用程序的根視圖中。它還應(yīng)突出顯示“current”按鈕。
實(shí)施完畢后,你的路由就完成了。你如何選擇重新加載#content元素中的內(nèi)容完全取決于你自己和你的后端設(shè)計(jì)。
以上就是如何制作自己的原生JavaScript路由的詳細(xì)內(nèi)容,更多關(guān)于制作原生JavaScript路由的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- 編寫(xiě)可維護(hù)面向?qū)ο蟮腏avaScript代碼[翻譯]
- 使用 JavaScript 創(chuàng)建可維護(hù)的幻燈片效果代碼
- 聊一聊JavaScript的URL對(duì)象是什么
- JavaScript中正則表達(dá)式的實(shí)際應(yīng)用詳解
- 如何用JavaScript實(shí)現(xiàn)一個(gè)數(shù)組惰性求值庫(kù)
- 詳解Javascript實(shí)踐中的命令模式
- 如何用JavaScript學(xué)習(xí)算法復(fù)雜度
- 用幾道面試題來(lái)看JavaScript執(zhí)行機(jī)制
- 教你如何寫(xiě)出可維護(hù)的JS代碼
相關(guān)文章
微信小程序?qū)崿F(xiàn)頁(yè)面浮動(dòng)導(dǎo)航
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)頁(yè)面浮動(dòng)導(dǎo)航,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-01-01
js實(shí)現(xiàn)頁(yè)面刷新滾動(dòng)條位置不變
本文介紹了js實(shí)現(xiàn)頁(yè)面刷新滾動(dòng)條位置不變的實(shí)例代碼,需要的朋友可以看下2016-11-11
JS this關(guān)鍵字在ajax中使用出現(xiàn)問(wèn)題解決方案
這篇文章主要介紹了JS this關(guān)鍵字在ajax中使用出現(xiàn)問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
uniapp開(kāi)發(fā)小程序?qū)崿F(xiàn)全局懸浮按鈕的代碼
這篇文章主要介紹了uniapp開(kāi)發(fā)小程序如何實(shí)現(xiàn)全局懸浮按鈕,但是在uniapp中式?jīng)]有window對(duì)象,和dom元素的,需要獲取頁(yè)面上節(jié)點(diǎn)的幾何信息,具體實(shí)例代碼詳細(xì)跟隨小編一起看看吧2022-03-03
JavaScript數(shù)據(jù)類(lèi)型學(xué)習(xí)筆記
這篇文章主要針對(duì)JavaScript數(shù)據(jù)類(lèi)型整理的學(xué)習(xí)筆記,分享給大家,感興趣的小伙伴們可以參考一下2016-01-01
JavaScript通過(guò)字符串調(diào)用函數(shù)的實(shí)現(xiàn)方法
這篇文章主要介紹了JavaScript通過(guò)字符串調(diào)用函數(shù)的實(shí)現(xiàn)方法,實(shí)例分析了javascript動(dòng)態(tài)調(diào)用函數(shù)的技巧,需要的朋友可以參考下2015-03-03
js驗(yàn)證身份證號(hào)有效性并提示對(duì)應(yīng)信息
這篇文章主要介紹了一段超級(jí)全面的二代身份證號(hào)碼驗(yàn)證程序,2015-10-10

