<!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" />
<title>Document</title>
</head>
<body>
<button id="btn1">home</button>
<button id="btn2">mine</button>
<div id="app"></div>
<script>
const home = document.querySelector('#btn1')
const mine = document.querySelector('#btn2')
/*
pushState 和 replaceState 会改变当前页面显示的url,但都不会刷新页面
popState 无法监听 pushState 和 replaceState
因此重写这两个方法 在这两个方法中添加自定义事件并派发
history模式需要服务器配置访问路径不存在时,指向index.html, 因为pushState和replaceState不刷新页面只改变url,若刷新页面则会导致浏览器向服务器请求url路径的资源
*/
class VueRouter {
constructor(router) {
this.router = router || []
this.curRoute = null
history.pushState = this.reWriteFn('pushState')
history.replaceState = this.reWriteFn('replaceState')
// 绑定this 不然this为window
this.getQuery = this.getQuery.bind(this)
this.popState = this.popState.bind(this)
window.addEventListener('pushState', this.getQuery)
// 在同一文档的两个历史记录条目之间导航会触发该事件 如histroy.back() 或点击前进后退按钮
window.addEventListener('popstate',this.popState)
}
reWriteFn(type) {
let fn = window.history[type]
// 函数柯里化
return function () {
/*
apply: xxx.apply(this,[xxx,xxxx])
bind: xxx.bind(this,xxx,xxxx)
call: xxx.call(this,xxx,xxxx)
apply 和 call 区别为, apply 传入数组作为参数, call 可以直接传参
bind 也可以直接传参, 但是bind是返回一个绑定this过后的函数, 需要自己去调用
*/
// 此处 this 为 history
console.log(this,'this')
let rw = fn.apply(this, arguments)
let e = new Event(type)
e.arguments = arguments
// 派发事件使得我们能够监听到pushState和replaceState
window.dispatchEvent(e)
return rw
}
}
getQuery(e) {
const { arguments: args } = e
let url = args[2].slice(1)
this.showComponent(url)
}
showComponent(url){
this.curRoute = this.router.find(route=>{
if(route.path == url){
return route
}
})
if(!this.curRoute) this.curRoute = this.router[0]
document.querySelector('#app').innerHTML = this.curRoute.component
}
push(state,title,url){
if(!url){
throw new Error('路由跳转不能缺少参数')
}
history.pushState(state, title, url)
}
popState(e){
/*
window.location.host = http://127.0.0.1:5500/mine
window.location.port = 5500
window.location.hostname = http://127.0.0.1
window.location.pathname = /mine
window.location.searchURL = ?xxx= xxx(查询参数)
window.location.hash = #xxx(hash值)
*/
// 获取URL的路径部分
const url = window.location.pathname || ''
this.showComponent(url)
}
}
home.addEventListener('click', () => {
Router.push({ state: 1 }, null, './home')
})
mine.addEventListener('click', () => {
Router.push({ state: 2 }, null, './mine')
})
const Router = new VueRouter([
{
path: '/home',
name: 'home',
component: '<div>主页</div>'
},
{
path: '/mine',
name: 'home',
component: '<div>我的</div>'
}
])
</script>
</body>
</html>
前端路由history简单实现
最新推荐文章于 2023-10-10 17:44:21 发布
文章介绍了一个简单的VueRouter实现,通过重写pushState和replaceState方法来监听路由变化,同时处理popstate事件,确保在history模式下正确展示页面组件。当点击home和mine按钮时,会更新#app内的内容,展示对应的主页或我的页面。
摘要由CSDN通过智能技术生成