Vue版本2+模拟VueRouter的history模式

分步骤实现

创建 VueRouter 类

/**
 * VueRouter Class
 * -------------------------------------
 * + options
 * + data
 * + routeMap
 * -------------------------------------
 * + Constructor(Option): VueRouter
 * _install(Vue): void
 * + init(): void
 * + initEvent: void
 * + CreateRouteMap(): void
 * + initComponents(Vue): void
 */

export default class VueRouter{
    
    
}

创建静态方法,实现 install

/**
 * VueRouter Class
 * -------------------------------------
 * + options
 * + data
 * + routeMap
 * -------------------------------------
 * + Constructor(Option): VueRouter
 * _install(Vue): void
 * + init(): void
 * + initEvent: void
 * + CreateRouteMap(): void
 * + initComponents(Vue): void
 */

export default class VueRouter{
    
    
    static install(Vue){
    
    
        // 1.判断当前插件是否被安装
        if(VueRouter.install.installed){
    
    
            return 
        }
        VueRouter.install.installed = true
        // 2.把 Vue 构造函数记录到全局变量
        _Vue = Vue
        // 3.把创建 Vue 实例的时候传入的 router 对象注入到 Vue 实例上
        // 混入
        _Vue.mixin({
    
    
            beforeCreate(){
    
    
                // router 执行,组件不执行
                if(this.$options.router){
    
    
                    _Vue.prototype.$router = this.$options.router
                }
            }
        })
    }
}

实现构造函数

/**
 * VueRouter Class
 * -------------------------------------
 * + options
 * + data
 * + routeMap
 * -------------------------------------
 * + Constructor(Option): VueRouter
 * _install(Vue): void
 * + init(): void
 * + initEvent: void
 * + CreateRouteMap(): void
 * + initComponents(Vue): void
 */

export default class VueRouter{
    
    
    static install(Vue){
    
    
        // 1.判断当前插件是否被安装
        if(VueRouter.install.installed){
    
    
            return 
        }
        VueRouter.install.installed = true
        // 2.把 Vue 构造函数记录到全局变量
        _Vue = Vue
        // 3.把创建 Vue 实例的时候传入的 router 对象注入到 Vue 实例上
        // 混入
        _Vue.mixin({
    
    
            beforeCreate(){
    
    
                // router 执行,组件不执行
                if(this.$options.router){
    
    
                    _Vue.prototype.$router = this.$options.router
                }
            }
        })
    }
    constructor(options){
    
    
        this.options = options
        this.routeMap = {
    
    }
        // 将 current 注册为响应式对象
        this.data = _Vue.observable({
    
     
            current: '/'
        })
    }
}

实现 createRouteMap

/**
 * VueRouter Class
 * -------------------------------------
 * + options
 * + data
 * + routeMap
 * -------------------------------------
 * + Constructor(Option): VueRouter
 * _install(Vue): void
 * + init(): void
 * + initEvent: void
 * + CreateRouteMap(): void
 * + initComponents(Vue): void
 */

export default class VueRouter{
    
    
    static install(Vue){
    
    
        // 1.判断当前插件是否被安装
        if(VueRouter.install.installed){
    
    
            return 
        }
        VueRouter.install.installed = true
        // 2.把 Vue 构造函数记录到全局变量
        _Vue = Vue
        // 3.把创建 Vue 实例的时候传入的 router 对象注入到 Vue 实例上
        // 混入
        _Vue.mixin({
    
    
            beforeCreate(){
    
    
                // router 执行,组件不执行
                if(this.$options.router){
    
    
                    _Vue.prototype.$router = this.$options.router
                }
            }
        })
    }
    constructor(options){
    
    
        this.options = options
        this.routeMap = {
    
    }
        // 将 current 注册为响应式对象
        this.data = _Vue.observable({
    
     
            current: '/'
        })
    }
    
    createRouteMap(){
    
    
        // 遍历所有的路由规则,把路由规则解析成键值对的形式 存储到 routeMap 中
        this.options.routes.forEach(route=>{
    
    
            this.routeMap[route.path] = route.component
        })
    }
}

实现 initComponents 方法 - router-link

/**
 * VueRouter Class
 * -------------------------------------
 * + options
 * + data
 * + routeMap
 * -------------------------------------
 * + Constructor(Option): VueRouter
 * _install(Vue): void
 * + init(): void
 * + initEvent: void
 * + CreateRouteMap(): void
 * + initComponents(Vue): void
 */

export default class VueRouter{
    
    
    static install(Vue){
    
    
        // 1.判断当前插件是否被安装
        if(VueRouter.install.installed){
    
    
            return 
        }
        VueRouter.install.installed = true
        // 2.把 Vue 构造函数记录到全局变量
        _Vue = Vue
        // 3.把创建 Vue 实例的时候传入的 router 对象注入到 Vue 实例上
        // 混入
        _Vue.mixin({
    
    
            beforeCreate(){
    
    
                // router 执行,组件不执行
                if(this.$options.router){
    
    
                    _Vue.prototype.$router = this.$options.router
                    this.$options.router.init()
                }
            }
        })
    }
    constructor(options){
    
    
        this.options = options
        this.routeMap = {
    
    }
        // 将 current 注册为响应式对象
        this.data = _Vue.observable({
    
     
            current: '/'
        })
    }

    init(){
    
    
        this.createRouteMap()
        this.initComponents(_Vue)
    }
    
    createRouteMap(){
    
    
        // 遍历所有的路由规则,把路由规则解析成键值对的形式 存储到 routeMap 中
        this.options.routes.forEach(route=>{
    
    
            this.routeMap[route.path] = route.component
        })
    }

    initComponents(Vue){
    
    
        const self = this
        Vue.component('route-link', {
    
    
            props: {
    
    
                to: String
            },
            template: '<a :href="to"><slot></slot></a>'
        })
    }
}

遇到问题:you are using the runtime-only build of Vue where the template compiler is not avriable. ...

还有一个 router-view 的报错先不用管,是没定义 router-view 组件

Vue的构建版本:
在这里插入图片描述
两种方式:
1、修改配置,新增 vue.config.js 配置文件,修改 runtimeCompiler: true
2、将 template 换成 render

更改为 render 函数

/**
 * VueRouter Class
 * -------------------------------------
 * + options
 * + data
 * + routeMap
 * -------------------------------------
 * + Constructor(Option): VueRouter
 * _install(Vue): void
 * + init(): void
 * + initEvent: void
 * + CreateRouteMap(): void
 * + initComponents(Vue): void
 */

export default class VueRouter{
    
    
    static install(Vue){
    
    
        // 1.判断当前插件是否被安装
        if(VueRouter.install.installed){
    
    
            return 
        }
        VueRouter.install.installed = true
        // 2.把 Vue 构造函数记录到全局变量
        _Vue = Vue
        // 3.把创建 Vue 实例的时候传入的 router 对象注入到 Vue 实例上
        // 混入
        _Vue.mixin({
    
    
            beforeCreate(){
    
    
                // router 执行,组件不执行
                if(this.$options.router){
    
    
                    _Vue.prototype.$router = this.$options.router
                    this.$options.router.init()
                }
            }
        })
    }
    constructor(options){
    
    
        this.options = options
        this.routeMap = {
    
    }
        // 将 current 注册为响应式对象
        this.data = _Vue.observable({
    
     
            current: '/'
        })
    }

    init(){
    
    
        this.createRouteMap()
        this.initComponents(_Vue)
    }
    
    createRouteMap(){
    
    
        // 遍历所有的路由规则,把路由规则解析成键值对的形式 存储到 routeMap 中
        this.options.routes.forEach(route=>{
    
    
            this.routeMap[route.path] = route.component
        })
    }

    initComponents(Vue){
    
    
        const self = this
        Vue.component('route-link', {
    
    
            props: {
    
    
                to: String
            },
            render(h){
    
    
                return h('a', {
    
    
                    attrs: {
    
    
                        href: this.to
                    },
                }, [this.$slots.default])
            },
            // template: '<a :href="to"><slot></slot></a>'
        })
    }
}

实现 initComponents 方法 - router-view

/**
 * VueRouter Class
 * -------------------------------------
 * + options
 * + data
 * + routeMap
 * -------------------------------------
 * + Constructor(Option): VueRouter
 * _install(Vue): void
 * + init(): void
 * + initEvent: void
 * + CreateRouteMap(): void
 * + initComponents(Vue): void
 */

export default class VueRouter{
    
    
    static install(Vue){
    
    
        // 1.判断当前插件是否被安装
        if(VueRouter.install.installed){
    
    
            return 
        }
        VueRouter.install.installed = true
        // 2.把 Vue 构造函数记录到全局变量
        _Vue = Vue
        // 3.把创建 Vue 实例的时候传入的 router 对象注入到 Vue 实例上
        // 混入
        _Vue.mixin({
    
    
            beforeCreate(){
    
    
                // router 执行,组件不执行
                if(this.$options.router){
    
    
                    _Vue.prototype.$router = this.$options.router
                    this.$options.router.init()
                }
            }
        })
    }
    constructor(options){
    
    
        this.options = options
        this.routeMap = {
    
    }
        // 将 current 注册为响应式对象
        this.data = _Vue.observable({
    
     
            current: '/'
        })
    }

    init(){
    
    
        this.createRouteMap()
        this.initComponents(_Vue)
    }
    
    createRouteMap(){
    
    
        // 遍历所有的路由规则,把路由规则解析成键值对的形式 存储到 routeMap 中
        this.options.routes.forEach(route=>{
    
    
            this.routeMap[route.path] = route.component
        })
    }

    initComponents(Vue){
    
    
        const self = this
        Vue.component('route-link', {
    
    
            props: {
    
    
                to: String
            },
            render(h){
    
    
                return h('a', {
    
    
                    attrs: {
    
    
                        href: this.to
                    },
                    on: {
    
    
                        click: this.clickHandler
                    } 
                }, [this.$slots.default])
            },
            methods: {
    
    
                clickHandler(e){
    
    
                    // 取消默认行为
                    e.preventDefault()
                    // pushState 改变地址栏,但是不向服务器发送请求
                    history.pushState({
    
    }, '', this.to)
                    // 当前路径记录到 current 里边
                    this.$router.data.current = this.to
                }
            }
            // template: '<a :href="to"><slot></slot></a>'
        })
        
        Vue.component('router-view',{
    
    
            // 由于 current 是响应式的,所以这里会自动渲染对应的组件
            render(h){
    
    
                const component = self.routeMap[self.data.current]
                return h(component)
            }
        })
    }
}

实现 initEvents

/**
 * VueRouter Class
 * -------------------------------------
 * + options
 * + data
 * + routeMap
 * -------------------------------------
 * + Constructor(Option): VueRouter
 * _install(Vue): void
 * + init(): void
 * + initEvent: void
 * + CreateRouteMap(): void
 * + initComponents(Vue): void
 */

export default class VueRouter{
    
    
    static install(Vue){
    
    
        // 1.判断当前插件是否被安装
        if(VueRouter.install.installed){
    
    
            return 
        }
        VueRouter.install.installed = true
        // 2.把 Vue 构造函数记录到全局变量
        _Vue = Vue
        // 3.把创建 Vue 实例的时候传入的 router 对象注入到 Vue 实例上
        // 混入
        _Vue.mixin({
    
    
            beforeCreate(){
    
    
                // router 执行,组件不执行
                if(this.$options.router){
    
    
                    _Vue.prototype.$router = this.$options.router
                    this.$options.router.init()
                }
            }
        })
    }
    constructor(options){
    
    
        this.options = options
        this.routeMap = {
    
    }
        // 将 current 注册为响应式对象
        this.data = _Vue.observable({
    
     
            current: '/'
        })
    }

    init(){
    
    
        this.createRouteMap()
        this.initComponents(_Vue)
        this.initEvent()
    }
    
    createRouteMap(){
    
    
        // 遍历所有的路由规则,把路由规则解析成键值对的形式 存储到 routeMap 中
        this.options.routes.forEach(route=>{
    
    
            this.routeMap[route.path] = route.component
        })
    }

    initComponents(Vue){
    
    
        const self = this
        Vue.component('route-link', {
    
    
            props: {
    
    
                to: String
            },
            render(h){
    
    
                return h('a', {
    
    
                    attrs: {
    
    
                        href: this.to
                    },
                    on: {
    
    
                        click: this.clickHandler
                    } 
                }, [this.$slots.default])
            },
            methods: {
    
    
                clickHandler(e){
    
    
                    // 取消默认行为
                    e.preventDefault()
                    // pushState 改变地址栏,但是不向服务器发送请求
                    history.pushState({
    
    }, '', this.to)
                    // 当前路径记录到 current 里边
                    this.$router.data.current = this.to
                }
            }
            // template: '<a :href="to"><slot></slot></a>'
        })
        
        Vue.component('router-view',{
    
    
            // 由于 current 是响应式的,所以这里会自动渲染对应的组件
            render(h){
    
    
                const component = self.routeMap[self.data.current]
                return h(component)
            }
        })
    }

    initEvent(){
    
    
        // 点击浏览器的前进后退按钮触发
        window.addEventListener('popstate', ()=>{
    
    
            this.data.current = window.location.pathname
        })
    }
}

完整代码

/**
 * VueRouter Class
 * -------------------------------------
 * + options
 * + data
 * + routeMap
 * -------------------------------------
 * + Constructor(Option): VueRouter
 * _install(Vue): void
 * + init(): void
 * + initEvent: void
 * + CreateRouteMap(): void
 * + initComponents(Vue): void
 */

export default class VueRouter{
    
    
    static install(Vue){
    
    
        // 1.判断当前插件是否被安装
        if(VueRouter.install.installed){
    
    
            return 
        }
        VueRouter.install.installed = true
        // 2.把 Vue 构造函数记录到全局变量
        _Vue = Vue
        // 3.把创建 Vue 实例的时候传入的 router 对象注入到 Vue 实例上
        // 混入
        _Vue.mixin({
    
    
            beforeCreate(){
    
    
                // router 执行,组件不执行
                if(this.$options.router){
    
    
                    _Vue.prototype.$router = this.$options.router
                    this.$options.router.init()
                }
            }
        })
    }
    constructor(options){
    
    
        this.options = options
        this.routeMap = {
    
    }
        // 将 current 注册为响应式对象
        this.data = _Vue.observable({
    
     
            current: '/'
        })
    }

    init(){
    
    
        this.createRouteMap()
        this.initComponents(_Vue)
        this.initEvent()
    }

    createRouteMap(){
    
    
        // 遍历所有的路由规则,把路由规则解析成键值对的形式 存储到 routeMap 中
        this.options.routes.forEach(route=>{
    
    
            this.routeMap[route.path] = route.component
        })
    }

    initComponents(Vue){
    
    
        const self = this
        Vue.component('route-link', {
    
    
            props: {
    
    
                to: String
            },
            render(h){
    
    
                return h('a', {
    
    
                    attrs: {
    
    
                        href: this.to
                    },
                    on: {
    
    
                        click: this.clickHandler
                    } 
                }, [this.$slots.default])
            },
            methods: {
    
    
                clickHandler(e){
    
    
                    // 取消默认行为
                    e.preventDefault()
                    // pushState 改变地址栏,但是不向服务器发送请求
                    history.pushState({
    
    }, '', this.to)
                    // 当前路径记录到 current 里边
                    this.$router.data.current = this.to
                }
            }
            // template: '<a :href="to"><slot></slot></a>'
        })
        Vue.component('router-view',{
    
    
            // 由于 current 是响应式的,所以这里会自动渲染对应的组件
            render(h){
    
    
                const component = self.routeMap[self.data.current]
                return h(component)
            }
        })
    }

    initEvent(){
    
    
        // 点击浏览器的前进后退按钮触发
        window.addEventListener('popstate', ()=>{
    
    
            this.data.current = window.location.pathname
        })
    }
}

注意这里只是模拟一下原理,里边还有其他的条条框框的限制判断等等其他处理就不完善了

猜你喜欢

转载自blog.csdn.net/qq_38652871/article/details/130511306
今日推荐