hash模式
<html>
<head>
<meta charset="UTF-8">
<title>Hash</title>
<style>
.nav_container {
display: grid;
justify-content: center;
width: 100%;
height: 80px;
background: #000;
grid-template-columns: repeat(auto-fit, minmax(100px, max-content));
grid-template-rows: 80px;
}
.nav_container > div a {
display: block;
height: 100%;
color: #fff;
padding: 0 30px;
line-height: 80px;
cursor: pointer;
}
.nav_container > div a.ac {
color: red !important;
}
a:link {
color:white;
}
a:visited {
color:white;
}
a:hover {
color:white;
}
</style>
</head>
<body>
<!-- <div id="test">Hello</div>-->
<!-- <div style="height: 2000px"></div>-->
<!-- <div style="cursor: pointer; position: fixed; right: 0; bottom: 0;"><a href="#test">⬆️</a></div>-->
<div class="nav_container">
<div><a class="ac" href="#home">Home</a></div>
<div><a href="#about">About</a></div>
<div><a href="#contact">Contact</a></div>
<div><a href="#other">Other</a></div>
</div>
<div id="app"></div>
</body>
<script>
const app = document.querySelector('#app');
const nav = document.querySelector('.nav_container');
const nav_child = document.querySelectorAll('.nav_container div a')
function init() {
nav.addEventListener('click', (e)=> {
console.log(e.parentNode);
if(e.target.nodeName === 'A') {
nav_child.forEach(el => {
el.className = '';
});
e.target.className = 'ac';
}
})
console.log(nav_child, nav);
}
init();
const routerCompMap = new Map([
["#home", "<h1>home</h1>"],
["#about", "<h1>about</h1>"],
["#contact", "<h1>Contact</h1>"]
]);
function renderPage(hash) {
const domStr = routerCompMap.get(hash) || "<h1>404</h1>";
app.innerHTML = domStr;
console.log("domStr", domStr);
}
document.addEventListener('DOMContentLoaded', ()=> {
window.addEventListener('hashchange', ()=> {
renderPage(window.location.hash);
});
renderPage(window.location.hash || '#home');
})
</script>
</html>
history模式
<html>
<head>
<meta charset="UTF-8">
<title>history</title>
<style>
.nav_container {
display: grid;
justify-content: center;
width: 100%;
height: 80px;
background: #000;
grid-template-columns: repeat(auto-fit, minmax(100px, max-content));
grid-template-rows: 80px;
}
.nav_container > div a {
display: block;
height: 100%;
color: #fff;
padding: 0 30px;
line-height: 80px;
cursor: pointer;
}
.nav_container > div a.ac {
color: red !important;
}
a:link {
color:white;
}
a:visited {
color:white;
}
a:hover {
color:white;
}
a[data-link] {
font-size: 30px;
}
</style>
</head>
<body>
<div class="nav_container">
<div><a class="ac" href="/home" data-link>Home</a></div>
<div><a href="/about" data-link>About</a></div>
<div><a href="/contact" data-link>Contact</a></div>
<div><a href="/other" data-link>Other</a></div>
</div>
<div id="app"></div>
<script>
let app = document.querySelector('#app');
const routerCompMap = new Map([
["/home", "<h1>home</h1>"],
["/about", "<h1>about</h1>"],
["/contact", "<h1>Contact</h1>"]
]);
function renderPage(hash) {
const domStr = routerCompMap.get(hash) || "<h1>404</h1>";
app.innerHTML = domStr;
console.log("domStr", domStr);
}
document.addEventListener('DOMContentLoaded', ()=> {
renderPage('/home');
document.querySelectorAll('a[data-link]').forEach(el => {
el.addEventListener('click', (e)=> {
e.preventDefault();
let path = e.target.getAttribute('href');
history.pushState(null, null, path);
renderPage(path);
console.log(path);
})
})
});
</script>
</body>
</html>
hash和history模式的區別
- 外觀:hash的url有個#符號,history沒有,history外觀更好看。
- 重新整理:hash重新整理會載入到位址列對應的頁面,history重新整理瀏覽器會重新發起請求,如果服務端沒有匹配當前的url,就會出現404頁面。
- 相容性:hash能相容到IE8,history只能相容到IE10。
- 服務端支援:hash(#及後面的內容)的變化不會導致瀏覽器向伺服器發起請求;history重新整理會重新向伺服器發起請求,需要在服務端做處理:如果沒有匹配到
- 原理:hash透過監聽瀏覽器的onhashchange()事件,查詢對應的路由規則;history利用H5新增的pushState()和replaceState()方法改變url。
- 記錄:hash模式只有#後面的內容被修改才會新增新的記錄棧;history透過pushState()設定的url於當前url一模一樣也會被記錄到歷史記錄棧。