Skip to content
本页目录

简易版实现

代码实现

JS
//  vue-router.js
class HistoryRoute{
    constructor(){
        this.current = null
    }
}
class VueRouter{
    constructor(options){
        this.options = options
        this.mode = options.mode || 'hash'
        this.routes = options.routes || []
        this.routesMap = this.createMap(this.routes)
        
        this.history = new HistoryRoute()
        this.init() // 初始化路由方法
    }

    //刷新页面就会调用
    init(){
        //使用的是hash路由
        if(this.mode === 'hash'){
            location.hash ? "" : location.hash = '/'
            
            // 首次进入页面时,让其路由改变以触发页面渲染
            window.addEventListener('load', () => {
                this.history.current = location.hash.slice(1)
            })

            window.addEventListener('hashchange', () => {
                this.history.current = location.hash.slice(1)
            })

        //使用的是history
        } else {
            location.pathname ? '' : location.pathname = '/'

            // 首次进入页面时,让其路由改变以触发页面渲染
            window.addEventListener('load', () => {
                this.history.current = location.pathname
            })

            window.addEventListener('popstate', () => {
                this.history.current = location.pathname
            })
        }
    }
    push(){}

    go(){}

    back(){}

    //可以把数组结构转化成对象结构
    createMap(routes){
        return routes.reduce((memo, current) => {
            // memo 刚开始是一个空对象
            memo[current.path] = current.component
            return memo;
        }, {})
    }
}

// install 方法中第一个参数就是 Vue 构造器
VueRouter.install = function(Vue){
    // 当使用Vue.use(Vue-router)时,调用install方法

    Vue.mixin({
        //给每个组件混入一个 beforeCreate 生命周期钩子
        beforeCreate(){
            // console.log(this.$options.name);
            // 获取根组件
            if(this.$options && this.$options.router){
                // 找到根组件
                // 把当前的实例挂载到 _root 上面
                this._root = this   // main 根组件

                // 把 router 实例挂载到 _router 上
                this._router = this.$options.router

                // 监控路径变化,路径变化就刷新视图 
                // 和 vue 劫持 data 一样,给 history 设置 get 和 set,使 history 变成响应式
                Vue.util.defineReactive(this, 'xxx', this._router, history)    
            }else{  // main ----> app    --->  Home/About   所有组件中都是有router
                this._root = this.$parent._root;
                this._router = this.$parent._router;
            }

            // this.$options.name 获取组件的名字
            Object.defineProperty(this, "$router", {
                get(){
                    return this._root._router;
                }
            })

            Object.defineProperty(this, "$route", {
                get(){
                    return{
                        current:this._root._router.history.current
                    }
                }
            })
        }
    })

    // Vue.component()  全局组件
    Vue.component('router-link', {
        props: {
            to: String
        },
        render(h) {
            let mode = this._self._root._router.mode;
            return <a href={mode==='hash'?`#${this.to}`:this.to}>{this.$slots.default}</a>
        }
    })
    Vue.component('router-view', {
        render(h) {
            let current = this._self._root._router.history.current;
            let routesMap = this._self._root._router.routesMap;
            return h(routesMap[current])
        }
    })
}

export default VueRouter
//  vue-router.js
class HistoryRoute{
    constructor(){
        this.current = null
    }
}
class VueRouter{
    constructor(options){
        this.options = options
        this.mode = options.mode || 'hash'
        this.routes = options.routes || []
        this.routesMap = this.createMap(this.routes)
        
        this.history = new HistoryRoute()
        this.init() // 初始化路由方法
    }

    //刷新页面就会调用
    init(){
        //使用的是hash路由
        if(this.mode === 'hash'){
            location.hash ? "" : location.hash = '/'
            
            // 首次进入页面时,让其路由改变以触发页面渲染
            window.addEventListener('load', () => {
                this.history.current = location.hash.slice(1)
            })

            window.addEventListener('hashchange', () => {
                this.history.current = location.hash.slice(1)
            })

        //使用的是history
        } else {
            location.pathname ? '' : location.pathname = '/'

            // 首次进入页面时,让其路由改变以触发页面渲染
            window.addEventListener('load', () => {
                this.history.current = location.pathname
            })

            window.addEventListener('popstate', () => {
                this.history.current = location.pathname
            })
        }
    }
    push(){}

    go(){}

    back(){}

    //可以把数组结构转化成对象结构
    createMap(routes){
        return routes.reduce((memo, current) => {
            // memo 刚开始是一个空对象
            memo[current.path] = current.component
            return memo;
        }, {})
    }
}

// install 方法中第一个参数就是 Vue 构造器
VueRouter.install = function(Vue){
    // 当使用Vue.use(Vue-router)时,调用install方法

    Vue.mixin({
        //给每个组件混入一个 beforeCreate 生命周期钩子
        beforeCreate(){
            // console.log(this.$options.name);
            // 获取根组件
            if(this.$options && this.$options.router){
                // 找到根组件
                // 把当前的实例挂载到 _root 上面
                this._root = this   // main 根组件

                // 把 router 实例挂载到 _router 上
                this._router = this.$options.router

                // 监控路径变化,路径变化就刷新视图 
                // 和 vue 劫持 data 一样,给 history 设置 get 和 set,使 history 变成响应式
                Vue.util.defineReactive(this, 'xxx', this._router, history)    
            }else{  // main ----> app    --->  Home/About   所有组件中都是有router
                this._root = this.$parent._root;
                this._router = this.$parent._router;
            }

            // this.$options.name 获取组件的名字
            Object.defineProperty(this, "$router", {
                get(){
                    return this._root._router;
                }
            })

            Object.defineProperty(this, "$route", {
                get(){
                    return{
                        current:this._root._router.history.current
                    }
                }
            })
        }
    })

    // Vue.component()  全局组件
    Vue.component('router-link', {
        props: {
            to: String
        },
        render(h) {
            let mode = this._self._root._router.mode;
            return <a href={mode==='hash'?`#${this.to}`:this.to}>{this.$slots.default}</a>
        }
    })
    Vue.component('router-view', {
        render(h) {
            let current = this._self._root._router.history.current;
            let routesMap = this._self._root._router.routesMap;
            return h(routesMap[current])
        }
    })
}

export default VueRouter

路由表

js
// routes.js
import Home from '../views/Home.vue'
import About from '../views/About.vue'
export default [
    {path:'/home', component: Home},
    {path:'/about', component: About},
]
// routes.js
import Home from '../views/Home.vue'
import About from '../views/About.vue'
export default [
    {path:'/home', component: Home},
    {path:'/about', component: About},
]

路由注册

JS
// index.js
import Vue from 'vue'
import VueRouter from './vue-router'
import routes from './routes'

//使用Vue.use就会调用install方法
Vue.use(VueRouter)

export default new VueRouter({
    mode:'history',
    routes
})
// index.js
import Vue from 'vue'
import VueRouter from './vue-router'
import routes from './routes'

//使用Vue.use就会调用install方法
Vue.use(VueRouter)

export default new VueRouter({
    mode:'history',
    routes
})