手撕Vue.js中的Vue-router(二):实现`router-view`(二)

245 阅读3分钟

前言

     书接上回,我们实现了动态组件<component :is="component"></component>动态组件但是页面内容并没有实现,本文将完全实现router-view.

页面展示实现

     我们使用hashchange方法获得Router对象,给对象中的url添加一个refurl的值发生改变时,router-view中的计算属性computed就会重新计算值。

// 在任何地方只要使用useRouter就可以拿到router对象
const useRouter = () => {
    return 
}
const createWebHashHistory = () =>{//控制history实例化对象
    // 给我们返回的是hisotry对象
    // 那么craeteWebHashHistory方法就是返回一个url
    function bindEvents(fn){
        window.addEventListener('hashchange',fn)
    }
    return {
        // 通过window拿到location地址 并且删除第一个`#` 如果没有那就是/
        url:window.location.hash.slice(1) || '/',
        bindEvents
    }
}
class Router {
// 添加一个构造方法
    constructor(options){
        this.history = options.history
        this.routes = options.routes
        console.log(options,'////');
        // 当前的url 状态 它是router-view中 component计算属性的依赖
        this.current = ref(this.history.url)
        this.history.bindEvents(()=>{
            //内部的this 指向router
            // 点击时自动更新当前的url
            this.current.value = window.location.hash.slice(1)
            console.log(this.current.value,'////');
        })
    }

我们定义一个bindEvents(fn)函数监听事件,当我们点击时,就会触发函数fn.我们提供一个useRouter方法,当我们调用函数,我们可以拿到router实例对象 也就是return new Router(options).监听事件的触发,我们需要对routerurl实现自动更新。

image.png

image.png

我们切换页面时,url也会更新成相应页面的url. 我们的useRoute是需要向外全局提供的,所以我们便可以使用app.provide(KEY,router)第二个参数是我们想要全局共享的对象 ,可以将对象挂载在app上,provide是向任何组件提供,这个KEY就可以与inject()方法配合使用。

// VueRouter 封装在这里
import { ref,inject} from 'vue';
import RouterLink from './RouterLink.vue'
import RouterView from './RouterView.vue'


const ROUTER_KEY = '__router__'
// 提供一个useRouter方法
// 在任何地方只要使用useRouter就可以拿到router对象
const useRouter = () => {
    // 当我们调用函数,我们可以拿到router实例对象 也就是return new Router(options)
    return inject(ROUTER_KEY)
}
const createRouter = (options) =>{//控制Router实例化对象
    return new Router(options)
}
// 返回一个hash的路由对象
// 路由对象由 url 
// hashchange 传一个fn 触发时,fn会作为时间处理函数
const createWebHashHistory = () =>{//控制history实例化对象
    // 给我们返回的是hisotry对象 
    // 那么craeteWebHashHistory方法就是返回一个url
    function bindEvents(fn){
        window.addEventListener('hashchange',fn)
    }
    return {
        // 通过window拿到location地址 并且删除第一个`#` 如果没有那就是/
        url:window.location.hash.slice(1) || '/',
        bindEvents
    }
}

class Router {
// 添加一个构造方法
    constructor(options){
        this.history = options.history
        this.routes = options.routes
        console.log(options,'////');
        // 当前的url 状态 它是router-view中 component计算属性的依赖
        this.current = ref(this.history.url)
        this.history.bindEvents(()=>{
            //内部的this 指向router
            // 点击时自动更新当前的url
            this.current.value = window.location.hash.slice(1)
            console.log(this.current.value,'////');
        })
    }
    // 提供一个install方法
    install(app){
        console.log(app);
        // console.log('vue 要对接vue-router');
        // 完成全局组件的声明
        app.provide(ROUTER_KEY,this)//谁都可以使用,向外提供router对象 全局
        app.component('router-link',RouterLink)
        app.component('router-view',RouterView)
    }
}

export {
    createRouter,
    createWebHashHistory,
    useRouter
}

这个时候我们回到RouterView.vue中去处理一些数据

image.png

image.png

image.png 这里我们打印router对象,原本我们写(route) => route.path === router.url但是对象中是不存在url的,我们检查对象中的值,current.value才是代表的地址,所以这里的判断语句我们写成 (route) => route.path === router.current.value. 最后在App.vue中加上<router-view/>就可以实现页面展示了。

image.png image.png