优秀的编程知识分享平台

网站首页 > 技术文章 正文

精通Vue(9):vue-router(2)路由嵌套如何实现的

nanyue 2025-10-19 10:24:05 技术文章 1 ℃

上篇说了vue-router的基本概念,这篇写下路由嵌套,还是一篇一个问题。

vue-router的思路

在vue-router的理念中,<router-view>是一个舞台,某个时刻只能渲染一个组件。这个容易理解,比如舞台上唱歌,一次只能一个人表演。具体的代码在上个例子中有比较详细的说明,现在看另一个问题,如下:

当组件B上台时,它内部也有一个router-view,这样app一共就有两个router-view。但是组件B的<router-view>只是给它的子组件找个出口,就好比一个部门内部还有一个表演场所,只供内部人员使用。

现在提出的问题是:为什么组件B-2渲染时,它不会跑到最外层的<router-view>而是在父组件的<router-view>中?刚接触这个东西的时候,我就很好奇这个问题。

vue-router源码解读

当解析组件的子菜单路由时,实际上已经形成了一个链式关系,最主要的一个字段就是parent,如下所示:

parent关系确定之后,接下再创建一个匹配项,是什么意思呢?

就是凡是和当前的路由项有关系的祖先,都被加入进来,比如对于/test/a来说,它的匹配项如下:

//伪码
['/test','/test/a']

假如嵌套的很深,如下:

//伪码
['/test','/test/a','/test/a/b',
 '/test/a/b/c'....]

总结:1、首先确定parent关系。是通过children递归得到的。2、确定match关系,是通过parent的链递归得到的。

开始渲染

当vue渲染app时,它内部有两层的router-view,那么每一层该渲染哪个组件呢?

<router-view>是一个组件,它有一个明确的render函数,在vue-router中有定义,我们进到源代码中,可以看到如下:

while (parent && parent._routerRoot !== parent) {
    var vnodeData = parent.$vnode ? parent.$vnode.data : {};
    if (vnodeData.routerView) {
        depth++;
    }
    if (vnodeData.keepAlive && parent._directInactive && parent._inactive) {
        inactive = true;
    }
    parent = parent.$parent;
}
data.routerViewDepth = depth;

在渲染之前,我们需要知道route已经确定了,也就是路由路径确定了,而route的matched也确定了。那么就根据router-view的parent计算view是第几层(从0开始),也就是深度,然后通过深度得到matched中的值。

比如渲染第一个router-view时,得到深度为0,就渲染/test组件。在渲染/test组件的过程中,又遇到一个<router-view>于是,计算它的深度为1,那么就取matched下标为1的位置,得到/test/a的组件。

总起来说就是,任何一个路由,不仅仅是把自身的组件规定好,而是整个app的所有<router-view>都规定好了,比如说,当我们定向到/test/a路由时,它把整个页面的<router-view>都规定好了,VUE只管按着matched渲染就好了。

深奥啊深奥,我是觉得这个代码写的非常复杂!!理解本质的唯一办法就是回到源码。

完整的调试代码

创建test-925.html文件,下面是完整的<body>代码。

<div id="app">
    <router-view></router-view>
</div>

<template id="test">
    <div>
        <h2>测试页面</h2>
        <router-view></router-view>
    </div>
</template>
<script>
    const routes = [
        {
            path: '/test-925.html',
            redirect: '/test/a'
        },
        {
            path: '/test',
            component: {
                template: '#test'
            },
            children: [
                {
                    path: 'a',
                    component: {
                            template: '<h2 style="color:red">我是/test/a对应的组件内容!!!</h2>'
                    }
                }
            ]
        }
    ]

    const router = new VueRouter({
        routes,
        mode: 'history',
        base: '/test-rsa/cmd/vue/router/'
    })
    new Vue({
        router
    }).$mount('#app')
</script>

总结

这篇解释了路由嵌套,它在开发中非常常见,从源码而不是书本上去解读它。

Tags:

最近发表
标签列表