Vue之手写最小版本的VueRouter,实现history模式路由的基本功能

let _Vue = null
export default class VueRouter {
    //vue在注册插件的时候,当插件是一个对象,会调用install 方法,传入两个参数,vue的构造函数和可选的选项对象
    static install(Vue) {
        //1.判断当前插件是否已经被安装
        if (VueRouter.install.installed) {
            return
        }
        VueRouter.install.installed = true
        //2.把vue的构造函数记录到全局变量,将来在VueRouter实例方法中,要使用vue的构造函数。比如创建router-link 和router-view 时,要使用vue.component 去创建
        _Vue = Vue
        //3,把创建vue 实例时传入的router 对象,注入到所有的vue实例上 将来要使用this.$router, 并且所有的组件也是vue实例
        //混入 ,在vue插件里面使用混入,给所有vue实例混入一个选项,
        _Vue.mixin({
            //将来所有的组件都会执行beforeCreate 这个钩子函数
            beforeCreate() {
                //只有vue的$options 中才有router 这个属性,而组件的$options 没有router
                if (this.$options.router) {
                    _Vue.prototype.$router = this.$options.router
                    this.$options.router.init()
                }
            }
        })
    }
    //构造函数需要接受一个选项对象,option,返回值是VueRouter对象,
    //在构造函数中需要初始化三个属性,options,data(存储当前路由地址,是个响应式对象),routeMap
    constructor(options) {
        this.options = options //维护构造函数中传入的选项,也就是路由规则等
        this.routeMap = {} //解析routes 也就是路由规则以后 存储到routeMap 键值对的形式,键就是地址,值就是组件
        this.data = _Vue.observable({ //创建响应式对象
            current: '/' //当前路由地址
        })
    }
    //遍历所有路由规则,变成键值对的形式,存储到routerMap 中
    createRouteMap() {
        this.options.routes.forEach(route => {
            this.routeMap[route.path] = route.component
        })
    }
    //创建 router-link 和 router-view
    initComponents(Vue) {
        const self = this
        Vue.component('router-link', {
            props: {
                to: String //检查传入的to 类型
            },
            // template: `
            //     <a :href="to">
            //         <slot></slot>
            //     </a>
            // `
            //运行时版本不支持template 选项
            //打包的时候,单文件的template 会编译成render 函数,此时需要手写render 函数
            render(h) {
                //h 函数的用法 第一个是 标签选择器,第二个是属性和时间,第三个是子元素
                return h('a', {
                    attrs: { //这是注册属性
                        href: this.to
                    },
                    on: { //这是注册事件
                        click: this.clickHandlder
                    }
                }, [this.$slots.default])
            },
            methods: {
                clickHandlder(e) {
                    history.pushState({ path: this.to }, null, this.to)
                    this.$router.data.current = this.to
                    e.preventDefault()
                }
            }
        })
        Vue.component('router-view', {
            render(h) {
                //1.找到当前路由地址对应的组件
                const component = self.routeMap[self.data.current]
                //2.调用h 函数创建虚拟DOM
                return h(component)
            }
        })
    }
    initEvent() {
        window.addEventListener('popstate', e => {
            if (e.state) {
                this.data.current = e.state.path
            } else {
                this.data.current = '/'
            }
        })
    }
    init() {
        this.createRouteMap()
        this.initComponents(_Vue)
        this.initEvent()
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值