RouterView
1、hash 模式
前端路由就是匹配不同的 URL 路径,进行解析,然后动态地渲染出区域 HTML 内容。但是这样存在URL 每次变化都会造成页面的刷新。?
在 2014 年之前,大家是通过 hash 来实现前端路由,URL hash 中的 # 就是类似于下面代码中的这种 # : http://www.xxx.com/#/login
之后,在进行页面跳转的操作时,hash 值的变化并不会导致浏览器页面的刷新,只是会触发 hashchange 事件。在下面的代码中,通过对 hashchange 事件的监听,我们就可以在 fn 函数内部进行动态地页面切换。
window.addEventListener('hashchange',fn)
2、history 模式
2014 年之后HTML5 标准发布多了两个 API:pushState 和 replaceState。我们可以改变 URL 地址,并且浏览器不会向后端发送请求,我们就能用另外一种方式实现前端路由 **。
在下面我们监听了 popstate 事件,可以监听到通过 pushState 修改路由的变化。并且在 fn 函数中,我们实现了页面的更新操作。 window.addEventListener('popstate', fn)
import {ref,inject} from 'vue'
const ROUTER_KEY = '__router__'
function createRouter(options){
return new Router(options)
}
function useRouter(){
return inject(ROUTER_KEY)
}
function createWebHashHistory(){
function bindEvents(fn){
window.addEventListener('hashchange',fn)
}
return {
bindEvents,
url:window.location.hash.slice(1) || '/'
}
}
class Router{
constructor(options){
this.history = options.history
this.routes = options.routes
this.current = ref(this.history.url)
this.history.bindEvents(()=>{
this.current.value = window.location.hash.slice(1)
})
}
install(app){
app.provide(ROUTER_KEY,this)
}
}
export {createRouter,createWebHashHistory,useRouter}
src/router/index.js
import {
createRouter,
createWebHashHistory,
} from './grouter/index'
const router = createRouter({
history: createWebHashHistory(),
routes
})
RouterView.vue
我们首先使用 useRouter 获取当前路由的实例;然后通过当前的路由,也就是 router.current.value 的值,在用户路由配置 route 中计算出匹配的组件;最后通过计算属性返回 comp 变量,在 template 内部使用 component 组件动态渲染。
<template>
<component :is="comp"></component>
</template>
<script setup>
import {computed } from 'vue'
import { useRouter } from '../grouter/index'
let router = useRouter()
const comp = computed(()=>{
const route = router.routes.find(
(route) => route.path === router.current.value
)
return route?route.component : null
})
</script>
RouterILink.vue ?
<template>
<a :href="'#'+props.to">
<slot />
</a>
</template>
<script setup>
import {defineProps} from 'vue'
let props = defineProps({
to:{type:String,required:true}
})
</script>
|