想搞懂vue-router里的RouterView,却被各种概念绕晕?别慌,这篇用问答形式把RouterView从基础到进阶的知识点掰碎了讲,新手也能轻松跟上~
RouterView到底是做什么的?
RouterView是vue-router提供的容器」,当你在项目里配置好路由规则(比如访问/home
时显示Home组件),RouterView就负责把匹配到的组件渲染到页面指定位置。
举个生活例子:你手机里的「微信」App,底部tab切换「聊天」「通讯录」「发现」时,顶部和底部导航栏不变,中间区域切换不同页面——这个中间可变的区域,就相当于RouterView的作用。
它还有个“好搭档”<RouterLink>
:<RouterLink>
负责生成可点击的导航(比如页面上的“首页”按钮),RouterView负责展示点击后对应的内容,两者配合完成「导航→渲染」的流程。
新手第一步:怎么在项目里用RouterView?
想用RouterView,得先把vue-router集成到项目里,步骤分3步:
安装并配置vue-router
如果是Vue3 + Vite项目,先装依赖:npm i vue-router
,然后在src/router/index.js
里配置路由规则:
import { createRouter, createWebHistory } from 'vue-router' // 导入要渲染的页面组件 import Home from '../views/Home.vue' const routes = [ { path: '/', // 访问根路径时 component: Home // 渲染Home组件 } ] const router = createRouter({ history: createWebHistory(), // 路由模式(还有hash模式等) routes // 上面定义的路由规则数组 }) export default router
把路由实例注入Vue应用
在main.js
里,把router挂载到App上:
import { createApp } from 'vue' import App from './App.vue' import router from './router' // 导入上面配置的router createApp(App) .use(router) // 注入路由 .mount('#app')
在模板里放RouterView
打开App.vue
(或其他需要渲染路由的组件),用<RouterView/>
占个“坑”:
<template> <div class="app-wrapper"> <!-- 导航区域,比如放RouterLink --> <nav> <RouterLink to="/">首页</RouterLink> </nav> <!-- 路由内容渲染区 --> <RouterView/> </div> </template> <script setup> import { RouterView, RouterLink } from 'vue-router' // 导入组件 </script>
这样一来,访问根路径时,Home组件就会自动渲染到<RouterView/>
的位置,整个“导航→渲染”的流程就跑通啦~
遇到复杂页面?RouterView和嵌套路由咋配合?
很多项目有「布局嵌套」需求:比如后台管理系统,顶部有导航栏、左侧有侧边栏,只有中间内容区随路由变化,这时候就得用「嵌套路由」,而RouterView是嵌套路由的核心载体。
配置嵌套路由规则
在路由配置里,给父路由加children
数组,代表子路由:
const routes = [ { path: '/admin', // 父路由路径 component: AdminLayout, // 父路由对应的布局组件(包含侧边栏、顶栏) children: [ { path: 'dashboard', // 子路由路径,完整路径是/admin/dashboard component: Dashboard // 子路由组件(中间内容区) }, { path: 'settings', component: Settings } ] } ]
父组件里放RouterView渲染子组件
打开AdminLayout.vue
(父布局组件),在需要渲染子内容的位置放<RouterView/>
:
<template> <div class="admin-layout"> <aside>左侧侧边栏(固定不变)</aside> <header>顶部导航(固定不变)</header> <main> <RouterView/> <!-- 这里渲染子路由的Dashboard或Settings --> </main> </div> </template>
这样访问/admin/dashboard
时,页面结构是:AdminLayout的侧边栏+顶栏 + RouterView渲染的Dashboard;切换到/admin/settings
时,中间区域自动换成Settings——完美实现“布局不变,内容切换”~
RouterView能传参吗?怎么给组件递数据?
必须能!常见场景比如“用户详情页需要根据ID展示信息”,这时候得把路由里的参数传给渲染的组件,主要有两种方式:
方式1:用路由参数($route.params
)
先在路由规则里定义动态参数(用参数名):
const routes = [ { path: '/user/:id', // :id是动态参数,比如访问/user/123,id就是123 component: User } ]
然后在User组件里,通过$route.params.id
获取参数:
<script setup> import { useRoute } from 'vue-router' const route = useRoute() console.log(route.params.id) // 输出路由里的id,比如123 </script>
方式2:用props解耦(更推荐)
如果想让组件不直接依赖$route
(更灵活、易测试),可以开启props
模式:
const routes = [ { path: '/user/:id', component: User, props: true // 开启后,路由参数会自动传给User组件的props } ]
然后User组件用props接收:
<script setup> const props = defineProps(['id']) // 接收id参数 console.log(props.id) // 同样能拿到123 </script>
方式3:在RouterView上直接传动态数据
如果想给所有匹配的路由组件传通用数据(比如全局配置),可以在<RouterView>
上用v-bind
传值:
<RouterView :theme="currentTheme" />
然后路由组件里用props接收theme
即可,不过这种方式适合全局通用数据,要是不同路由需要不同数据,结合「路由元信息(meta)」更灵活~
切换路由时页面状态总丢失?RouterView怎么缓存?
比如表单页面,切出去再回来,输入的内容没了;或者列表页,滚动位置重置了——这时候得给RouterView加缓存,保留组件状态,Vue的<KeepAlive>
组件就是干这个的~
基础用法:用KeepAlive包裹RouterView
在模板里,把<RouterView>
包在<KeepAlive>
里:
<template> <div> <KeepAlive> <RouterView/> </KeepAlive> </div> </template>
这样一来,路由切换时,已渲染的组件实例会被缓存,组件的生命周期钩子(比如onMounted
)不会重复执行、滚动位置这些状态就保留下来了~
进阶:控制哪些组件缓存(按需缓存)
如果不是所有页面都要缓存(比如登录页不需要),可以用<KeepAlive>
的include/exclude
属性,或者结合「路由元信息(meta)」:
<template> <KeepAlive :include="keepAliveComponents"> <RouterView/> </KeepAlive> </template> <script setup> import { computed } from 'vue' import { useRouter } from 'vue-router' const router = useRouter() // 根据当前路由的meta.keepAlive,动态决定是否缓存 const keepAliveComponents = computed(() => { return router.currentRoute.value.meta.keepAlive ? [router.currentRoute.value.name] : [] }) </script>
然后在路由配置里标记哪些页面要缓存:
const routes = [ { path: '/profile', component: Profile, name: 'Profile', // 要和上面的name对应 meta: { keepAlive: true } // 标记需要缓存 }, { path: '/login', component: Login, meta: { keepAlive: false } // 不需要缓存 } ]
这样只有标记了keepAlive: true
的组件会被缓存,灵活性拉满~
页面没匹配到路由?RouterView的fallback咋用?
当用户访问了不存在的路径(比如/xxx
),RouterView默认啥都不渲染,但我们可以用fallback
属性给个“兜底”提示,比如404页面:
方式1:用fallback属性
<RouterView fallback="抱歉,页面走丢了~"/>
这样没匹配到路由时,会显示“抱歉,页面走丢了~”。
方式2:用插槽自定义内容
如果想搞复杂点的兜底(比如加个404组件、按钮),用插槽更灵活:
<RouterView> <template #fallback> <div class="error-page"> <h1>404 - 页面不存在</h1> <RouterLink to="/">返回首页</RouterLink> </div> </template> </RouterView>
路由配置里要记得加「通配符路由」()放在最后,确保能匹配到所有无效路径:
const routes = [ // 其他路由... { path: '/:pathMatch(.*)*', // 匹配所有未定义的路径 component: Error404 } ]
这样结合fallback和通配符路由,用户访问错误路径时体验更友好~
一个页面要渲染多个区域?RouterView的命名视图是啥?
比如做博客详情页,需要同时渲染「文章内容」「评论区」「相关推荐」三个独立组件,这时候命名视图就能派上用场——给RouterView起不同名字,对应渲染不同组件。
配置命名视图的路由规则
路由规则里用components
(注意是复数),给每个组件分配名字:
const routes = [ { path: '/blog/:id', components: { default: Article, // 对应没有name的RouterView comments: Comments, // 对应name="comments"的RouterView related: RelatedPosts // 对应name="related"的RouterView } } ]
模板里用命名RouterView
在页面模板里,给RouterView加name
属性,对应路由里的键:
<template> <div class="blog-detail"> <!-- 渲染Article组件(default对应的RouterView) --> <RouterView/> <!-- 渲染Comments组件 --> <RouterView name="comments"/> <!-- 渲染RelatedPosts组件 --> <RouterView name="related"/> </div> </template>
这样访问/blog/123
时,三个区域会同时渲染对应的组件,实现“多区域并行渲染”的效果~
性能优化:RouterView和异步组件、动态路由咋结合?
项目大了,首屏加载慢?用「异步组件(懒加载)」让RouterView只在需要时加载组件代码;业务复杂,需要动态切换组件?用「动态路由」让RouterView根据条件渲染不同组件。
异步组件(懒加载)
路由配置里,把component
改成函数形式,访问时才加载组件代码:
const routes = [ { path: '/about', component: () => import('../views/About.vue') // 访问/about时才加载About.vue } ]
RouterView会正常渲染异步加载的组件,加载过程中可以加个loading状态提示(比如在App.vue里监听路由加载状态)。
动态路由(根据条件切换组件)
比如根据用户角色,显示不同的后台首页:
const routes = [ { path: '/dashboard', component: () => { const role = localStorage.getItem('role') // 假设从本地存贮取角色 return role === 'admin' ? import('../views/AdminDashboard.vue') : import('../views/UserDashboard.vue') } } ]
这样RouterView会根据用户角色,动态渲染AdminDashboard或UserDashboard——一套路由,适配多场景~
看完这些,是不是觉得RouterView没那么难了?总结下:它是路由内容的“展示容器”,能配合嵌套路由、传参、缓存、命名视图等玩法,帮我们搞定单页应用的各种复杂场景,多动手写demo,结合项目需求去试,很快就能掌握啦~如果还有疑问,评论区随时喊我~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。