手写 vue-router

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>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值