HTML5 history api
前言
由於筆者在網路上沒有找到比較好的關於 history api
的實踐案例,有的案例過於雜亂,沒有重點,有些案例只是告訴讀者 api
是什麼,卻沒告訴怎麼用,本文章從零開始帶讀者實踐 history api
,建議和筆者一起寫一遍。
效果
注意 url
變化,另外用到了 虎褲里老師 和 狼大老師 的圖,侵權馬上刪。
流程
-
html
部分需要引入
jquery
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./index.css" />
<script src="./jquery.js"></script>
<script src="./index.js"></script>
<title>history html5</title>
</head>
<body>
<div class="row">
<button data-id="1" data-name="tiger" class="btn">來一隻虎虎</button>
<button data-id="0" data-name="cow" class="btn">來一隻牛牛</button>
</div>
<div class="row">
<img class="image" />
</div>
</body>
</html>
css
部分
.row {
display: flex;
justify-content: space-around;
}
.image {
width: 25%;
height: 25%;
padding: 20px;
cursor: pointer;
}
- 等待頁面
dom
載入完畢再執行JS
window.onload = () => {
// ...
}
-
獲取
btn
新增事件獲取請求所需的
id
以及介面需要展示的url
路徑
const btns = document.querySelectorAll(".btn");
btns.forEach(btn => {
const dataId = btn.getAttribute("data-id"); // 請求 id
const dataName = btn.getAttribute("data-name"); // 頁面 url 路徑
btn.addEventListener("click", () => {
// ...
});
});
-
模擬網路請求
接上方的程式碼,這裡的話我寫了一份模擬資料
{
"images": [
"./images/牛牛.jpg",
"./images/虎虎.jpg"
]
}
並在對應資料夾下存放了圖片,接下來進行 ajax
網路請求
btn.addEventListener("click", () => {
$.ajax({
url: "./mock/mock.json",
success: (res) => {
const { images } = res;
const state = images[dataId];
displayContent(state); // 接下來會提到這個函式
history.pushState(state, null, dataName); // 接下來會提到這個函式
},
});
});
這裡的話,一般來說是傳入 id
給服務端返回一個圖片的 url
由於為了實現簡單,全部返回後,根據先前從 dom
屬性上獲得的 dataId
獲取圖片的 url
- 根據獲得的
url
進行展示
const image = document.querySelector(".image");
const displayContent = (src) => {
image.setAttribute("src", src);
};
- 頁面變化後,利用
html5 history api
進行修改頁面地址,並傳入state
history.pushState(state, null, dataName);
其中第一個引數後面有個監聽事件會用到,而第二個引數代表標題,沒必要傳,第三個引數是路徑。
如果當前路徑是 /history
則如果傳入的路徑是 cow
則會變成 /history/cow
經過上面的幾個步驟,已經成功完成了利用按鈕切換介面的時候,展示不同的圖片資訊。
這個時候,如果點選返回或者頁面的前進按鈕,跳轉到上一頁或下一頁,是無法顯示網頁資訊的。
- 前進後退顯示網頁資訊
window.addEventListener("popstate", (e) => {
const { state } = e;
if (state) displayContent(state);
});
這裡的 state
就是前面 pushState
傳的 state
,可以根據這個 state
渲染當前介面,這就保證了在前進後退的時候渲染對應的影像。
這個時候當我們點選前進和後退的時候,基本是已經可以展示對應的介面的,這樣非常好,但是仍然有個問題,當後退到第一個介面的時候,沒有資料
- 替換第一個介面的資料
history.replaceState("./images/虎虎.jpg", null, location.href);
image.setAttribute("src", "./images/虎虎.jpg");
這裡的話,把第一個介面的資料補充上,其實一般都是經過網路請求的,這裡省略了。現在還存在一個問題,如果跳到某個介面後,重新整理,可能會出現獲取不到資源的情況。
這很正常,例如我們在 /history
下有一個 index.html
檔案,那麼訪問 /history
是可以直接訪問到這個檔案的,但是當我們通過上述方法跳轉路由的時候 /history/cow
並不存在 index.html
檔案,這意味重新整理介面後獲取不到對應的資源了,這個時候上線後還需要 nginx
的輔助配置
- 通過
nginx
的url
rewrite
配置,使得總是命中history/
總結
不知道大家有沒有用過之前的 vue router
裡面如果開啟了 mode: history
的話,最後還要通過 nginx
進行輔助配置,可能就是這個原理。