在多页应用的开发中,每个页面都是独立的HTML文件。当用户在应用中导航到新页面时,浏览器会发送全新的HTTP请求到服务器,获取该页面的所有资源(HTML、CSS、Javascript),也就是说,每次页面跳转都会经历一个完整的加载过程,当网速较慢或浏览器性能较低时,就会出现白屏页面,让用户不明所以,直接离开网站。
那么有什么方法既能不刷新整个页面,又能完成页面跳转呢?一起来看看vue3中hashRouter的实现原理.....
一、vue3中的hashRouter
import { createRouter, createWebHashHistory } from 'vue-router'
引入模块。- 实例化并配置路由,
css
const router = createRouter({
history: createWebHashHistory(),
routes : [
{
path: '/home',
component: ()=>import('../views/Home.vue')
},
{
path: '/bot',
component: () => import('../views/Bot.vue')
},
{
path: '/hot',
name:'hot',
component: () => import('../views/Hot.vue'),
}
]
})
- 使用
createWebHashHistory()
创建的路由器会在URL中使用#
字符作为前缀来区分不同的路由。 - 当
URL
的hash
部分为/home
时,加载Home.vue
组件...... hash
部分指的是URL
中#
符号后面跟随的字符串。
当我们进行类似导航栏的功能时,只有部分内容被动态更新,而无需重新加载整个页面,提供了非常流畅的用户体验,类似原生应用的感觉,同时可以减少浏览器负载,不需要频繁的请求完整的页面资源。
二、锚链接实现改变URL的hash部分
我们看见了vue3中页面更新时只有URL的hash部分发生了改变,那么有什么方法能改变这部分呢?
使用锚链接
在HTML中,使用<a>
标签结合hash来创建锚链接。用户点击锚链接时,window.location.hash将被更新,从而触发hashchange事件,这是接下来hashRouter实现的核心。
三、、手写hashRouter
基本原理
使用纯Javascript来监听hashchange事件,根据hash的变化来更新DOM。
xml
<body>
<nav id="nav">
<ul>
<li><a href="#/page1">page1</a></li>
<li><a href="#/page2">page2</a></li>
<li><a href="#/page3">page3</a></li>
</ul>
</nav>
<div id="container"></div>
<script>
class HashRouter{
constructor(){
this.routes = {} //page => Component
window.addEventListener('hashchange',
this.load.bind(this),false)
}
register(hash,callback = function(){}){
this.routes[hash] = callback
}
load(){
let hash = location.hash.slice(1) //去掉# 就是路由
console.log(hash,'///');
let handler
if(!hash){
//首页
handler = this.routes['/index']
}else{
//相应页面
handler = this.routes[hash]
}
handler && handler.call(this)
}
//注册首页
registerIndex(callback = function(){}){
this.routes['/index'] = callback
}
}
let router = new HashRouter()
let container = document.getElementById('container')
router.registerIndex(()=>{
container.innerHTML = '我是首页'
})
router.register('/page1',()=>{
container.innerHTML = '我是page1'
})
router.register('/page2',function(){
console.log(this,this.routes);
container.innerHTML = '我是page2'
})
router.register('/page3',()=>{
container.innerHTML = '我是page3'
})
console.log(router.routes);//查看添加的方法,用于handler执行
router.load()
</script>
</body>
hashchage
事件监听器,监听hash部分的内容变化。- 注册路由函数
register
,接收两个参数,一个为要注册路由的hash部分,一个为回调函数。 - 加载路由函数load,获取URL中的hash部分,输出控制台,清晰明了的看一下是什么东西,
handle
函数,执行对应hash部分的routes中的函数,用于相应页面的显示。 - 如果hash部分为空,则执行
routes
中'/index'所对应的函数,如果不为空,执行相应hash部分的函数,并显示相应页面。 handler && handler.call(this)
判断routes
中是否存在handler
是很有必要的,因为用户在输入URL中可能输错,这是handler
为undefined
,程序崩溃,这样使代码更加健壮。.call
确保了函数内部的this正确指向HashRouter
实例对象,方便拿到实例对象的所有信息,便于后续操作。- 单独创建注册首页函数,功能和注册路由函数
register
差不多。
实例化HashRouter
对象,执行构造函数constructor
中的逻辑。 注册几个页面的路由,实际上是往构造函数中的this.routes = {}
中添加方法,用于handler的执行。router.load()
完成进页面时的首次加载。
我们在看一下routes中的内容和handle函数的this指向。
handler执行routes中'/page2'对应的函数时,this指向的是实例对象HashRouter
,routes
的内容是对应hash部分内容和执行函数(改变container.innerHTML
模拟页面改变)