路由
-
路由(routing)就是通过互联的网络把信息从源地址传输到目的地址的活动。路由引导分组转送,经过一些中间的节点后,到它们最后的目的地。作成硬件的话,则称为路由器。路由通常根据路由表——一个存储到各个目的地的最佳路径的表——来引导分组转送。因此为了有效率的转送分组,创建存储在路由器存储器内的路由表是非常重要的。
-
路由就是分发请求,路由器就是分发请求的东西。
代码:
index.js
const number = window.location.hash.substr(1)
//获取用户想去哪里
const div = document.querySelector(`#div${number}`)
const app = document.querySelector("#app")
//获取界面
div.style.display = "block"
//渲染界面
app.appendChild(div)
//展示界面
如何切换页面(hash)
-
页面跳转的过程中,检测到路由的变化,并将相应的内容渲染到页面中
-
如何检测路由的变化?
window.location.hash
通过window.location.hash 可以获得路由地址,获得的路由地址会自带一个“#”
window.addEventListener("hashchange", () => {
console.log("hash 变了")
})
然后我们只需要监听 hashchange 事件,就可以检测路由的变化
默认路由
- 如果#1,#2,#3,#4都不写,就会报错,就给默认值:
number = number || 1(如果number存在,number就等于number,如果不存在,number就等于1)
404路由/保底路由
- 如果什么输入的什么都不是,我就返回404的页面;或者不写,我就返回我默认的页面
index.html:
<body>
<div id="app"></div>
<a href="#1">go to 1</a>
<a href="#2">go to 2</a>
<a href="#3">go to 3</a>
<a href="#4">go to 4</a>
<div id="div1" style="display:none">1</div>
<div id="div2" style="display:none">2</div>
<div id="div3" style="display:none">3</div>
<div id="div4" style="display:none">4</div>
<div id="div404" style="display:none">
你要找的网页不存在
</div>
<script src="src/index.js"></script>
</body>
index.js:
function route(){
let number = window.location.hash.substr(1)
let app = document.querySelector('#app')
number = number || 1
let div = document.querySelector(`#div${number}`)
if(!div) {
div = document.querySelector("#div404")
}
div.style.display = "block"
if(app.children.length > 0){
app.children[0].style.display = "none"
document.body.appendChild(app.children[0])
}
app.appendChild(div)
}
route()
window.addEventListener("hashchange", ()=>{
console.log('hash 变了')
route()
})
嵌套路由
路由表
获得 window.location.hash 的值以后,怎么将他跳转到相应页面呢,那就需要一个 hash 页面的映射表了,也就是路由表 (表驱动编程的体现)
const app = document.querySelector('#app')
const div1 = document.createElement("div")
div1.innerHTML = "1"
const div2 = document.createElement("div")
div1.innerHTML = "2"
const div3 = document.createElement("div")
div1.innerHTML = "3"
const div4 = document.createElement("div")
div1.innerHTML = "4"
const routeTable = {
"1": div1,
"2": div2,
"3": div3,
"4": div4
}
function route(container){
let number = window.location.hash.substr(1)
number = number || 1
//获取界面
let div = routeTable[number.toString()]
if(!div) {
div = document.querySelector("#div404")
}
div.style.display = "block"
//展示界面
container.innerHTML = ""
container.appendChild(div)
}
route(app)
window.addEventListener("hashchange", ()=>{
console.log('hash 变了')
route(app)
})
- 这就是一个的简易
hash前端路由了
hash模式?history模式?memory模式?
hash: 任何情况下都能做前端的路由,但是会SEO不友好(服务器收不到hash)
history:后端将所有前端路由都渲染到统一页面,除404页面,(IE8以下不支持)
memory:既不用hash,又不用history,用一个对象来存储
- 获取number的三种方式:
hash:window.location.hash.substr(1)
history: window.location.pathname
memory: window.localStorage.getItem("xxx")
history模式
history:后端将所有前端路由都渲染到统一页面,除404页面,(IE8以下不支持)
- hash模式请求路径时,会自带一个
#,而history模式则会自带一个/
代码:
index.html
<body>
<a class = "link" href="/1">go to 1</a>
<a class = "link" href="/2">go to 2</a>
<a class = "link" href="/3">go to 3</a>
<a class = "link" href="/4">go to 4</a>
<div id="app"></div>
<div id="div404" style="display: none;">你要找的内容被狗吃了</div>
<script src="src/index.js"></script>
</body>
index.js
const app = document.querySelector("#app");
const div1 = document.createElement("div");
div1.innerHTML = "1";
const div2 = document.createElement("div");
div2.innerHTML = "2";
const div3 = document.createElement("div");
div3.innerHTML = "3";
const div4 = document.createElement("div");
div4.innerHTML = "4";
const routeTable = {
"/1": div1,
"/2": div2,
"/3": div3,
"/4": div4
};
function route(container) {
let number = window.location.pathname; //获取值
if (number === "/") {
number = "/1"
}
// 获取界面
let div = routeTable[number.toString()];
if (!div) {
div = document.querySelector("#div404");
}
div.style.display = "block";
// 展示界面
container.innerHTML = "";
container.appendChild(div);
}
const allA = document.querySelectorAll("a.link")
for(let a of allA){
a.addEventListener("click", e => {
e.preventDefault() //阻止默认事件(不想让它刷新)
const href = a.getAttribute("href")
window.history.pushState(null, `page ${href}`, href)
//通知
onStateChange(href)
})
}
route(app);
function onStateChange() {
console.log("state 变了");
route(app);
}
-
通过 history 模式进行页面切换,会有一个问题,就是跳转的时候,同时会刷新页面,由于页面的跳转需要通过
a标签实现,而a标签默认是会跳转的,我们首先需要阻止a标签的默认事件,并得到href,然后使用window.history.pushState()进行跳转。 -
history.pushState()方法向当前浏览器会话的历史堆栈中添加一个状态(state) -
注意:
pushState()不会造成hashchange (en-US)事件调用,即使新的 URL 和之前的 URL 只是锚的数据不同。
memory模式
memory:既不用hash,又不用history,用一个对象来存储
index.js
function route(container) {
let number = window.localStorage.getItem("xxx");
if (!number ) {
number = "/1"
}
// 获取界面
let div = routeTable[number.toString()];
if (!div) {
div = document.querySelector("#div404");
}
div.style.display = "block";
// 展示界面
container.innerHTML = "";
container.appendChild(div);
}
const allA = document.querySelectorAll("a.link")
for(let a of allA){
a.addEventListener("click", e => {
e.preventDefault()
const href = a.getAttribute("href")
window.localStorage.getItem("xxx")
//通知
onStateChange(href)
})
}
route(app);
function onStateChange() {
console.log("state 变了");
route(app);
}
- 把路径存在用户看不见的地方,这种模式适合非浏览器。
总结: hash模式和history模式是通过URL来存储路径的,而memory模式是非URL,前端一般放在LocalStorage里面,移动端放在本地的数据库里面。memory模式的缺点是没有URL,分享给其他人之后,进入都会是初始状态,所以只对单机有效。