vue2的vue-router路由嵌套实现(源码分析和实现)

路由实例
router/index.js

import Vue from 'vue'
import Router from '../demoTools/kVue-router/router'
// import Router from 'vue-router'
Vue.use(Router)

/* 初始路由-静态路由 */
const routes = [
    {
        path: '/',
        component: () => import('@/views/index.vue')
    },
    {
        path: '/goods',
        component: () => import('@/views/goods.vue'),
        redirect: '/info',
        children: [
            {
                path: '/shopCar',
                component: () => import('@/views/shopCar.vue')
            },
             {
                path: '/orders',
                component: () => import('@/views/orders.vue')
            }
        ]
    }
]
const router = new Router({
    mode: 'hash',
    routes
})

export default router
// vue-router
// 保存vue的构造函数 插件中需要用到
import krouterView from './krouter-view'
import krouterLink from './krouter-link'
let Vue

class VueRouter {
    constructor(options) {
        // 将new传入的属性存储
        this.$options = options

        // 定义一个存储当前路由变量
        // currentRouter需要是响应式数据 可以实时变化 以方便router-view的函数再次执行
        // vue提供响应式的api
        this.currentRouter = window.location.hash.slice(1) || '/'
        
        // match匹配
        Vue.util.defineReactive(this, 'matched', [])
        this.match()

        // 监听hash的变化
        window.addEventListener('hashchange', this.onchange.bind(this))
    }

    onchange() {
        // window.location.hash 获取的值 #/home
        this.currentRouter = window.location.hash.slice(1)

        // 清空路由数组
        this.matched = []
        this.match()
    }

    match(routes) {
        routes = routes || this.$options.routes

        // 递归遍历
        for (const route of routes) {
         // 处理路由完全匹配
            if (
                route.path === '/' &&
                this.currentRouter.indexOf(route.path) !== -1
            ) {
                this.matched.push(route)
            }

            // about/info
            if (
                route.path !== '/' &&
                this.currentRouter.indexOf(route.path) !== -1
            ) {
                this.matched.push(route)
                if (route.children) {
                    this.match(route.children)
                }
                return
            }
        }
    }
}

// Vue.use(VueRouter)其实就是调用的install的方法
// Vue.use调用会传入_vue参数
VueRouter.install = function(_vue) {
    Vue = _vue

    // 挂载$router属性
    // this.$router.push()
    // 全局混入方式实现
    // 全局混入目的:延迟下面逻辑到router创建完毕并且附加到选项上时才执行
    Vue.mixin({
        beforeCreate() {
            // 每个组件调用都会执行
            /* 判断
            new Vue({
                router,
                render: h => h(App)
            }).$mount('#app');

            是否有router属性 存在的话挂载在Vue
          */
            if (this.$options.router) {
                Vue.prototype.$router = this.$options.router
            }
        }
    })

    // 注册并且实现组件router-view
    Vue.component('router-link', krouterLink)

    //  注册并且实现组件router-link
    Vue.component('router-view', krouterView)
}

export default VueRouter

krouter-view.js

/*  路由嵌套实现思路
1、标记路由嵌套层数
2、路由匹配获取代表深度层级的matched数组
*/
export default {
    // 获取当前路由对应组件
    render(h) {
        // 标记当前router-view深度
        this.$vnode.data.routerView = true

        // 路由嵌套层数计算
        let depath = 0
        let parent = this.$parent

        while (parent) {
            const vnodeData = parent.$vnode && parent.$vnode.data
            if (vnodeData) {
                if (vnodeData.routerView) {
                    depath++
                }
            }
            parent = parent.$parent
        }

        // 定义存储组件变量
        let components = null

        // 查找到对应组件赋值
        console.log(depath, '基层')
        const route = this.$router.matched[depath]
        console.log(route, '哈哈')
        if (route) {
            components = route.component
        }
        // 渲染对应组件
        return h(components)
    }
}

krouter-link.js

export default {
    props: {
        to: {
            type: String,
            required: true
        }
    },
    render(h) {
        // <a href='to'>xxx</a>
        // this.$slots.default 获取默认插槽内容 获取home about
        // hash模式需要 '#'
        // 虚拟dom设置a标签属性和值
        return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default)
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

追逐梦想之路_随笔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值