背景
- 单页面
众多周知,我们前端在开发的时候,一般将一个index.html 页面放在后端。这个 index.html即我们访问的单页面。我们在首次访问时直接访问后端部署的index.html路径即可。在请求到这个index.html页面后,后续切换页面展示内容不需要再次请求,这正是由于路由的作用。 - 路由
通过某种方式,监听用户动作行为,进而展示不同的内容 - 两种路由
众所周知,前端现在流行两种路由模式,history和hash模式
hash模式
-
原理
不同路由对应的hash值不一样,在改变hash值时并不会重新发送请求。 -
实现原理
根据浏览器提供的hashchange方法,监听不同hashchange进而引入不同的内容显示 -
具体实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</meta>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
</meta>
<meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover"
name="viewport">
</meta>
<title>hash模式</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 100%;
height: 100%;
}
.tag {
width: 100%;
display: flex;
justify-content: space-around;
}
.app {
width: 100%;
font-size: 15px;
}
</style>
</head>
<body>
<div class="tag">
<a href="#/">首页</a>
<a href="#/shop">商品</a>
<a href="#/mine">我的</a>
</div>
<div id="app" class="app"></div>
</body>
<script>
class VueRouter {
constructor(routes = []) {
this.routes = routes;
this.currHash = '';
this.refresh = this.refresh.bind(this);
window.addEventListener('load', this.refresh, false);
window.addEventListener('hashchange', this.refresh, false);// 重点监听hashchange方法
}
// 获得hash值
getHashValue(url) {
return url.indexOf('#') >= 0 ? url.slice(url.indexOf('#') + 1) : '/';
}
// 刷新
refresh(event){
let newHash = '',oldHash = '';
if(event.newURL){
oldHash = this.getHashValue(event.oldURL || '');
newHash = this.getHashValue(event.newURL||''); // 页面之间跳转使用
}
else {
newHash = this.getHashValue(window.location.hash); // 初次加载时跳转
}
this.currHash = newHash;
this.matchComponent();
}
// 插入html
matchComponent(){
let curRoute = this.routes.find(route=>route.path===this.currHash) // 找到当前路由配置的route
if(!curRoute){
curRoute = this.routes.find(route=>route.path === '/') // 找不到取默认第一个
}
const {component} = curRoute;
console.log(component);
document.querySelector('#app').innerHTML = component; // 渲染html
}
}
const router = new VueRouter([
{
path:'/',
name:"home",
component:'<div>首页</div>'
}, {
path:'/shop',
name:"shop",
component:'<div>商品</div>'
},
{
path:'/mine',
name:"mine",
component:'<div>我的</div>'
}
])
</script>
</html>
- 特点
1 只需在前端操作 无需后端辅助
2 使用hashchange监听,渲染不同页面
3 改变路由在url中#后面
history模式
- 原理
通过浏览器提供的 pushstate和replacestate。pushstate增加浏览器的会话历史栈,replacestate替换当前的会话历史,故不会重新请求url。 但是因为popstate不能监控到pushstate和replacestate,所以我们需要自定义监控事件,合适的时机抛出 - 具体实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</meta>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
</meta>
<meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover"
name="viewport">
</meta>
<title>history模式</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 100%;
height: 100%;
}
.tag {
width: 100%;
display: flex;
justify-content: space-around;
}
.app {
width: 100%;
font-size: 15px;
}
</style>
</head>
<body>
<div class="tag">
<div id="button1">首页</div>
<div id="button2">商品</div>
<div id="button3">我的</div>
</div>
<div id="app" class="app"></div>
</body>
<script>
// 改写事件,合适时机抛出
let _wr =function(type){
let origin = history[type] // 获取调用的方法;
return function(){
console.log(origin)
let res = origin.apply(this,arguments); // argument 即进行的路由
let e = new Event(type) ; // 创建自定义抛出事件
e.arguments = arguments;
window.dispatchEvent(e) ;// 抛出 可以监听
return res;
}
}
history.pushState = _wr('pushState');
history.replaceState = _wr("replaceState");// 改写方法
const btn1 = document.querySelector('#button1');
const btn2 = document.querySelector('#button2');
const btn3 = document.querySelector('#button3');
btn1.addEventListener('click',()=>{
history.pushState({ state:1 },null,'./home') // 三个参数 状态 标题(大都忽略)URL
})
btn2.addEventListener('click',()=>{
history.pushState({state:2},null,'./shop')
})
btn3.addEventListener('click',()=>{
history.pushState({state:3},null,'./mine')
})
window.addEventListener('pushState',(e)=>{
// 根据 e中参数 查找到
console.log(e.arguments)
// router.matchComponent(e.) // 调用获取路由然后展示
})
class VueRouter {
constructor(routes = []) {
this.routes = routes;
}
matchComponent(){
let curRoute = this.routes.find(route=>route.path===this.currHash) // 找到当前路由配置的route
if(!curRoute){
curRoute = this.routes.find(route=>route.path === '/') // 找不到取默认第一个
}
const {component} = curRoute;
console.log(component);
document.querySelector('#app').innerHTML = component; // 渲染html
}
}
const router = new VueRouter([
{
path:'/',
name:"home",
component:'<div>首页</div>'
}, {
path:'/shop',
name:"shop",
component:'<div>商品</div>'
},
{
path:'/mine',
name:"mine",
component:'<div>我的</div>'
}
])
</script>
</html>
- 特点
1 通过pushstate来进行路由切换,无需刷新页面
2 路径URL比较清晰
3 切换路由后** 刷新会报错** ,需要后端帮忙Nginx重新请求到index.html
参考文章
1 .[https://juejin.cn/post/7127143415879303204][https://juejin.cn/post/7127143415879303204]