web面试题
本人是一个web前端开发工程师,主要是vue框架,整理了一些面试题,今后也会一直更新,有好题目的同学欢迎评论区分享 ;-)
web面试题专栏:点击此处
文章目录
前言
history和hash都是利用浏览器的两种特性实现前端路由
以下代码示例用原生HTML,不用vue框架实现。
一、特点
hash的特点
- url后面写#锚点,由于 hash 值变化不会导致浏览器向服务器发出请求,而且hash 改变会触发 hashchange 事件(hashchange只能改变 # 后面的url片段)。
- 因为hash发生变化的url都会被浏览器记录下来,从而你会发现浏览器的前进后退都可以用了,所以人们在html5 的 history 出现前,基本都是使用 hash 来实现前端路由的。
- hash本来是拿来做页面定位的,如果拿来做路由的话,原来的锚点功能就不能用了。
history的特点
- hash 能兼容到IE8, history 只能兼容到 IE10,histroy兼容性不好。
- 如果后台没有配置,刷新可能导致404。(后面源码可重现)
- hash 的传参是基于 url 的,如果要传递复杂的数据,会有体积的限制,而history模式不仅可以在url里放参数,还可以将数据存放在一个特定的对象中。
二、监听
单纯打印 location 信息,不做业务处理,演示用~
hash的监听方式
// 监听hash模式
window.addEventListener("hashchange", (e) => {
console.log("hash:", location.hash);
});
histroy的监听方式
// 监听history模式
// 只能监听history.go、histroy.back()、history.forward()
window.addEventListener('popstate', (e) => {
console.log('onpopstate:', e, location.pathname)
})
// history.replaceState(),以及history.pushState() 需要重写
let rawReplace = history.replaceState
history.replaceState = (...arg) => {
rawReplace.apply(history, arg)
console.log('replaceState change...')
}
let rawPush = history.pushState
history.pushState = (...arg) => {
rawPush.apply(history, arg)
console.log('pushState change...')
}
三、改变url的方式
通过手动或者JS的方法修改url,已达到触发监听事件。
hash改变url的方式
- 通过浏览器输入栏手动输入网址来达到修改;
- 通过浏览器的前进后退方式;
- JS的方式location.href=“#/xxx”。
histroy改变url的方式
- 通过浏览器的前进后退方式;
- JS的方式 history.pushState() 切换路由前的url会保存在history中;
- JS的方式 history.replaceState() 切换路由前的url不会保存在history中;
- JS的方式 go()方法可以在用户的历史记录中任意跳转。这个方法接收一个参数,表示向后或向前跳转的页面数的一个整数值。负数表示向后跳转(类似于后退按钮),正数表示向前跳转(类似于前进按钮)
history.go(0)等于刷新
; - JS的方式 back()方法用于模仿浏览器的后退按钮,相当于history.go(-1);
- JS的方式 forward()方法用于模仿浏览器的前进按钮,相当于history.go(1)。
四、源码
hash的源码
<!--
* @Author: Penk
* @LastEditors: Penk
* @LastEditTime: 2023-10-13 10:09:15
* @FilePath: \web-interview-questions\路由\hash路由.html
* @email: 492934056@qq.com
-->
<!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" />
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<title>Document</title>
<style>
.codeBox {
background-color: black;
padding: 10px;
color: white;
}
</style>
</head>
<body style="margin-top: 50px; margin-left: 50px">
<main>
<button id="hashBtn">随机hash路由</button>
<br />
<span style="color: red; font-size: 12px">打开控制台可以看数据</span>
<p>hash的监听:</p>
<div class="codeBox">
<code>
window.addEventListener("hashchange", (e) => {
<br />
console.log("hash:", location.hash);
<br />
});
</code>
</div>
<p>hash的变化方式:</p>
<ul>
<li>通过浏览器输入栏手动输入网址来达到修改</li>
<li>通过浏览器的前进后退方式</li>
<li>JS的方式location.href="#/xxx"</li>
</ul>
<p>特点:</p>
<ul>
<li>
url后面写#锚点,由于 hash 值变化不会导致浏览器向服务器发出请求,而且
hash 改变会触发 hashchange 事件(hashchange只能改变 #
后面的url片段)。
</li>
<li>
因为hash发生变化的url都会被浏览器记录下来,从而你会发现浏览器的前进后退都可以用了,所以人们在
html5 的 history 出现前,基本都是使用 hash 来实现前端路由的。
</li>
</ul>
</main>
<script>
// 监听hash模式
window.addEventListener("hashchange", (e) => {
console.log("hash:", location.hash);
});
// 点击
$("#hashBtn").click((e) => {
location.href = "#/user" + Math.floor(Math.random() * 100);
});
</script>
</body>
</html>
history的源码
<!--
* @Author: Penk
* @LastEditors: Penk
* @LastEditTime: 2023-10-13 10:31:10
* @FilePath: \web-interview-questions\路由\history路由.html
* @email: 492934056@qq.com
-->
<!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" />
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<title>Document</title>
<style>
button+button {
margin-left: 20px;
}
.codeBox {
background-color: black;
padding: 10px;
color: white;
}
</style>
</head>
<body style="margin-top: 50px; margin-left: 50px">
<main>
<button id="pushStateBtn">pushState跳转,监听不了</button>
<button id="replaceStateBtn">replaceState跳转,监听不了</button>
<button id="goBtn">go(0)跳转,如果没有配置会返回404</button>
<button id="backBtn">back跳转,popstate监听到了</button>
<button id="forwardBtn">forward跳转,popstate监听到了</button>
<button id="gotoHome">跳转到首页,测试用</button>
<br />
<span style="color: red; font-size: 12px">打开控制台可以看数据</span>
<p>history的监听:</p>
<div class="codeBox">
<code>
window.addEventListener("popstate", (e) => {
<br />
console.log("onpopstate:", e, location.pathname);
<br />
});
<br />
// history.replaceState(),以及history.pushState() 需要重写
<br />
let rawReplace = history.replaceState;
<br />
history.replaceState = (...arg) => {
<br />
rawReplace.apply(history, arg);
<br />
console.log("replaceState change...");
<br />
}
<br />
<br />
let rawPush = history.pushState;
<br />
history.pushState = (...arg) => {
<br />
rawPush.apply(history, arg);
<br />
console.log("pushState change...");
<br />
}
<br />
</code>
</div>
<p>history的变化方式:</p>
<ul>
<li>通过浏览器的前进后退方式</li>
<li>JS的方式 history.pushState() 切换路由前的url会保存在history中,并不会出发popstate</li>
<li>
JS的方式 history.replaceState() 切换路由前的url不会保存在history中,并不会出发popstate
</li>
<li>
JS的方式 go()方法可以在用户的历史记录中任意跳转。
这个方法接收一个参数,表示向后或向前跳转的页面数的一个整数值。
负数表示向后跳转(类似于后退按钮),正数表示向前跳转(类似于前进按钮)。 history.go(0)等于刷新
</li>
<li>JS的方式 back()方法用于模仿浏览器的后退按钮,相当于history.go(-1),可以出发popstate</li>
<li>
JS的方式 forward()方法用于模仿浏览器的前进按钮,相当于history.go(1),可以出发popstate
</li>
</ul>
<p>特点:</p>
<ul>
<li>hash 能兼容到IE8, history 只能兼容到 IE10。</li>
<li>hash 本来是拿来做页面定位的,如果拿来做路由的话,原来的锚点功能就不能用了。</li>
<li>如果后台没有配置,刷新可能导致404。</li>
<li>
hash 的传参是基于 url 的,如果要传递复杂的数据,会有体积的限制,而 history
模式不仅可以在url里放参数,还可以将数据存放在一个特定的对象中。
</li>
</ul>
</main>
<script>
// 监听history模式
// 只能监听history.go、histroy.back()、history.forward()
window.addEventListener('popstate', (e) => {
console.log('onpopstate:', e, location.pathname)
})
// history.replaceState(),以及history.pushState() 需要重写
let rawReplace = history.replaceState
history.replaceState = (...arg) => {
rawReplace.apply(history, arg)
console.log('replaceState change...')
}
let rawPush = history.pushState
history.pushState = (...arg) => {
rawPush.apply(history, arg)
console.log('pushState change...')
}
$('#pushStateBtn').click((e) => {
let name = 'user' + Math.floor(Math.random() * 100)
const state = {
name
}
history.pushState(state, '', name)
console.log('执行pushState,并不能触发popstate事件,只有浏览器前进后退才可以。')
})
$('#replaceStateBtn').click((e) => {
history.replaceState(
{
name: 'user' + Math.floor(Math.random() * 100)
},
null,
'user' + Math.floor(Math.random() * 100)
)
console.log('执行replaceState,并不能触发popstate事件,只有浏览器前进后退才可以。')
})
$('#goBtn').click((e) => {
history.go(0)
})
$('#backBtn').click((e) => {
history.back()
})
$('#forwardBtn').click((e) => {
history.forward()
})
let href = window.location.href
$('#gotoHome').click((e) => {
location.href = href
})
</script>
</body>
</html>