JavaScript
Browser APIs
History API
เรียนรู้การควบคุม browser history ด้วย pushState และ replaceState เปลี่ยน URL โดยไม่ reload หน้า และรับ Back/Forward ด้วย popstate event
History API คืออะไร
History API คือ browser API ที่ให้ JavaScript ควบคุม history stack ของเบราว์เซอร์ — เปลี่ยน URL ในแถบที่อยู่, เพิ่มหรือแทนที่ entry ใน history โดยที่หน้าเว็บไม่ reload ประโยชน์หลัก: ทำให้ Single Page Application (SPA) มี URL เฉพาะสำหรับแต่ละ "หน้า" ได้ — ผู้ใช้กด Back/Forward ได้ตามปกติ และสามารถ bookmark หรือแชร์ link ได้
| method | ผล | เพิ่ม history entry |
|---|---|---|
| `history.pushState()` | เปลี่ยน URL + เพิ่ม entry ใหม่ | ใช่ |
| `history.replaceState()` | เปลี่ยน URL + แทนที่ entry ปัจจุบัน | ไม่ |
| `history.back()` | ย้อนกลับ 1 หน้า | — |
| `history.forward()` | ไปข้างหน้า 1 หน้า | — |
| `history.go(n)` | ไป n หน้า (ลบ = ย้อน, บวก = ไปข้างหน้า) | — |
history.pushState — เพิ่ม entry ใน history stack
syntax: `history.pushState(state, title, url)` - `state` — object ที่เก็บข้อมูลของหน้านั้น (ดึงกลับได้ใน `popstate` event) - `title` — ชื่อหน้า (browser ส่วนใหญ่ยังไม่ใช้ ใส่ `""` ได้) - `url` — URL ใหม่ที่ต้องการแสดง (ต้องอยู่ใน origin เดียวกัน)
URL ที่ใส่ต้องเป็น path ใน origin เดียวกัน — ใส่ต่าง domain จะ throw SecurityError
// URL เปลี่ยนเป็น /about โดยไม่ reload
history.pushState({ page: "about" }, "", "/about");
console.log(location.pathname); // "/about"
// ผู้ใช้กด Back จะกลับมาที่ URL เดิม
history.pushState({ page: "contact" }, "", "/contact");
// ตอนนี้ Back จะไป /about แล้วไป URL เดิมก่อนหน้าhistory.replaceState — แทนที่ entry ปัจจุบัน
ใช้ syntax เดียวกับ `pushState` แต่แทนที่ entry ปัจจุบันแทนที่จะเพิ่มใหม่ — ผู้ใช้กด Back จะไม่กลับมาที่ URL นี้ เหมาะสำหรับอัปเดต URL ระหว่าง flow เดียวกัน เช่น step ใน wizard หรือ filter ใน search
// อัปเดต URL ให้สะท้อน filter ปัจจุบัน
// โดยไม่เพิ่ม history entry (Back จะข้ามไป)
history.replaceState(
{ filter: "active" },
"",
"/tasks?status=active"
);popstate — ตรวจจับการกด Back / Forward
`popstate` event เกิดขึ้นเมื่อผู้ใช้กด Back หรือ Forward (หรือเมื่อเรียก `history.go()`) — ใช้เพื่ออัปเดต UI ให้ตรงกับ URL ใหม่ `event.state` คือ object ที่ส่งไปใน `pushState` หรือ `replaceState` ครั้งที่สร้าง entry นั้น
`popstate` ไม่เกิดเมื่อเรียก pushState/replaceState โดยตรง — เกิดเฉพาะเมื่อ user กด Back/Forward หรือ history.go()
window.addEventListener("popstate", function(event) {
console.log("URL ใหม่:", location.pathname);
console.log("state:", event.state);
// อัปเดต UI ตาม state
if (event.state && event.state.page) {
renderPage(event.state.page);
}
});
function renderPage(page) {
document.querySelector("#content").textContent = "กำลังแสดงหน้า: " + page;
}ข้อควรระวัง
- **URL ต้องอยู่ใน origin เดียวกัน** — `pushState` ไปต่าง domain จะ throw `SecurityError` — ใส่ได้เฉพาะ path, query string หรือ hash
- **popstate ไม่เกิดเมื่อ pushState** — ต้องฟัง popstate แยกเพื่อรับ Back/Forward — การเรียก pushState เองไม่ trigger event
- **reload หน้าต้อง handle บน server** — ถ้าผู้ใช้กด refresh ที่ /about เบราว์เซอร์จะ request /about จาก server จริงๆ — server ต้องส่ง HTML กลับมา ไม่ใช่ 404
- **state ต้องเป็น serializable** — object ใน state ต้องแปลงเป็น JSON ได้ — ใส่ function หรือ DOM element ไม่ได้