切换导航
简历
工具
演示
查询
导航菜单
服务端
30
前端
114
数据库
82
进阶开发
8
桌面程序
2
QA
15
软件使用
36
规范协议
5
操作系统
11
AI
0
复用资源
6
硬件
0
标签
HTML
正则表达式
Json
包管理工具
vite
CSS
XPath
JavaScript
Jquery
less
ES6
Vue
React
vue 3
Layui
editor.md
sea.js
Zepto.js
mysql.js
mssql.js
NodeJs
Express
前端template
YAML
杂项
外部链接
.NET Core SDK和运行时安装包
淘宝 NPM 镜像
查询网
Tables Generator线上表格转换工具
引用cdn在线脚本和样式
首页
前端
Vue Router 路由组件传参
[TOC] ## 将 props 传递给路由组件 在你的组件中使用 $route 或 useRoute() 会与路由紧密耦合,这限制了组件的灵活性,因为它只能用于特定的 URL。虽然这不一定是件坏事,但我们可以通过 props 配置来解除这种行为: 回到我们之前的示例: ```HTML <template> <div>User {{ $route.params.id }}</div> </template> ``` ```JS import User from './User.vue' // 传入 `createRouter` const routes = [{ path: '/users/:id', component: User }] ``` 我们可以通过声明 prop 来在 User.vue 中删除对 $route 的直接依赖: |组合模式|选项模式| |--|--| ||| 然后我们可以通过设置 props: true 来配置路由将 id 参数作为 prop 传递给组件: ```js const routes = [{ path: '/user/:id', component: User, props: true }] ``` ### 布尔模式 当 props 设置为 true 时,route.params 将被设置为组件的 props。 ### 命名视图 对于有命名视图的路由,你必须为每个命名视图定义 props 配置: ```js const routes = [ { path: '/user/:id', components: { default: User, sidebar: Sidebar }, props: { default: true, sidebar: false }, }, ] ``` ### 对象模式 当 props 是一个对象时,它将原样设置为组件 props。当 props 是静态的时候很有用。 ```js const routes = [ { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false, // 固定值 false source: 'newsletter' // 还可以传多个 } }, ] ``` 目标组件 ```HTML <template> <div class="promotion"> <h2>促销活动页面</h2> <p>来源:{{ source }}</p> <p> 弹窗状态(newsletterPopup): <span :style="{ color: newsletterPopup ? 'green' : 'red' }"> {{ newsletterPopup ? '显示' : '不显示' }} </span> </p> </div> </template> <script> export default { name: 'Promotion', // 必须声明接收的 props,名称要和路由配置中的键名一致 props: ['newsletterPopup', 'source'] } </script> ``` **为什么使用对象模式** + 传递固定配置:比如根据不同的促销活动来源(邮件、短信、广告)传入不同的弹窗开关或埋点参数。 + 不用写额外的模板代码:如果不用 props,你可能会在组件里硬编码,或者通过 $route 对象自己解析数据,这样组件和路由耦合度高。 + 保持组件纯粹:组件只需要声明 props,不关心数据来自路由参数还是静态对象,可复用性更好。 > **常见误区提醒** + 忘记在组件中声明 props:如果不写 props: ['newsletterPopup'],组件内部将无法访问该数据。 + 对象模式的数据不会响应路由变化:因为它是静态的,路由变化时不会重新求值(除非路由重新进入)。 + 不要试图在组件内修改 prop:应遵循单向数据流,如需修改请抛出自定义事件。 ### 函数模式 函数模式 允许你把 props 定义成一个函数,这个函数接收当前 route 对象作为参数,然后返回一个对象,该对象的每个属性会作为组件的 prop 传递。这允许你将参数转换为其他类型,将静态值与基于路由的值相结合等等。 + 相比于对象模式,函数模式可以 动态计算 props,比如从路由参数、查询字符串、或自定义逻辑中提取数据。 + 典型场景:将 URL 查询参数(?key=value)映射为组件的 prop,或者对参数进行类型转换、数据加工。 + 保持无状态:函数内部不应依赖外部状态(如 Vuex 的 state、组件实例的 data),因为该函数只在路由变化时执行,不会自动响应外部状态的变化。如果需要状态,请使用包装组件(后面会解释)。 + **router.js** ```js const routes = [ { path: '/search', name: 'search', component: SearchUser, // 🔥 函数模式:从查询参数 q 中提取值作为 prop props: (route) => ({ query: route.query.q // 例如 ?q=vue => { query: 'vue' } }) } ] ``` + **SearchUser.vue** ```HTML <template> <div> <h2>用户搜索</h2> <input v-model="keyword" @keyup.enter="search" /> <button @click="search">搜索</button> <p>当前搜索词:{{ query }}</p> <ul><li v-for="u in users" :key="u.id">{{ u.name }}</li></ul> </div> </template> <script setup> import { ref, watch } from 'vue' import { useRouter } from 'vue-router' const props = defineProps(['query']) const router = useRouter() const keyword = ref(props.query || '') const users = ref([]) const search = () => { router.push({ query: { q: keyword.value } }) } watch(() => props.query, async (newQ) => { keyword.value = newQ || '' if (newQ) { // 模拟 API 调用 const res = await fakeSearch(newQ) users.value = res } else { users.value = [] } }, { immediate: true }) async function fakeSearch(q) { await new Promise(r => setTimeout(r, 300)) return [{ id: 1, name: `结果:${q}` }] } </script> ``` + **App.vue** ```HTML <template> <div> <nav> <router-link to="/search?q=vue">搜索 vue</router-link> | <router-link to="/search?q=react">搜索 react</router-link> </nav> <router-view /> </div> </template> ``` **运行效果** + 访问 /search?q=vue,组件会接收到 props.query = 'vue',并自动发起搜索。 + 在输入框中输入新词并点击搜索,会通过 router.push 更新 URL 为 /search?q=新词,路由变化导致 props 函数重新执行,新的 query 值传入组件,触发搜索。 + 可以直接修改地址栏中的 ?q= 参数,组件也会响应。 **函数模式的其他实用场景** + 类型转换:props: route => ({ id: Number(route.params.id) }) + 合并静态数据和动态数据:props: route => ({ page: route.query.page || 1, defaultLimit: 10 }) + 处理多个查询参数:props: route => ({ filters: route.query }) + 保护敏感参数:只传递白名单中的字段 #### 保持 props 函数无状态 **有状态错误示例** ```js // ❌ 不要这样做 let count = 0 props: (route) => ({ query: route.query.q, counter: count++ // 每次路由变化都会递增,导致不可预测的行为 }) ``` 因为 props 函数只在路由变化时被调用,它不是响应式的,也不会随着 Vue 组件的重新渲染而重新执行。如果你在里面依赖了外部状态(如 Date.now()、全局计数、Vuex state),可能出现与 UI 不同步的问题。 正确做法:如果确实需要依赖响应式状态(比如当前登录用户的权限),应该使用包装组件:在路由组件外包裹一层,把状态作为普通 prop 传入,或者直接在组件内部通过 useRoute() 获取路由信息,但那样就失去了 props 解耦的意义。 ### 通过 RouterView 你还可以通过 `<RouterView>` 插槽 传递任意参数,`<RouterView v-slot>` 的核心原理:在 Vue Router 4 中,`<RouterView>` 组件可以通过作用域插槽(scoped slot) 暴露内部状态: ```HTML <RouterView v-slot="{ Component, route }"> <!-- 手动渲染匹配到的路由组件 --> </RouterView> ``` **暴露的对象包含两个最重要的属性:** + Component:当前路由匹配到的组件(是一个组件对象,不是虚拟 DOM) + route:当前路由对象(包含路径、参数、查询字符串等) 拿到 Component 后,你可以用 `<component :is="Component">` 手动渲染它,并且可以在该组件上随意添加任何 props 或 attribute。这就相当于你自己控制了“如何将路由组件渲染到视图上”。 #### 简单示例 + 路由配置 ```js { path: '/solt', name: 'solt', components: () => import('@study/slot.vue')} ``` + RouterView 使用插槽路由 ```HTML <RouterView v-slot="{ Component }"> <component :is="Component" view-prop="value" /> </RouterView> ``` + slot.vue 插槽 ```HTML <script setup> defineProps({ viewProp: String }) </script> <template> <div class="card">传的值:{{ viewProp }} </div> </template> ``` >** Tips:**但是,假如 slot.vue,却忘记声明 viewProp prop,Vue 在开发环境会抛出一个警告: Extraneous non-props attributes (view-prop) were passed to component but could not be automatically inherited... 虽然页面还能显示,但非预期的 prop 会作为 HTML attribute 渲染到根元素上,可能引起样式或行为异常。 > **WARNING** 在这种情况下,所有视图组件都会接收到 view-prop。通常这并不是一个好主意,因为这意味着所有的视图组件都声明了一个 view-prop prop,但这未必需要。所以请尽可能使用上述的其他选项。 #### 使用场景 虽然通常不推荐,但在少数场景下,这种“手动渲染 + 传递额外 prop”的方式非常有用: + 对路由组件进行包装(添加过渡动画、keep-alive、错误边界) ```HTML <RouterView v-slot="{ Component }"> <transition name="fade" mode="out-in"> <KeepAlive> <component :is="Component" /> </KeepAlive> </transition> </RouterView> ``` 这里并没有传递额外 prop,只是利用了插槽来自定义渲染结构。 + 根据路由动态添加不同的 prop 值 ```HTML <RouterView v-slot="{ Component, route }"> <component :is="Component" :role="route.meta.requiredRole" :pageId="route.params.id" /> </RouterView> ``` 每个路由组件都能收到基于当前路由动态计算的 prop,省去在每个组件内使用 useRoute() 的重复代码。 ### 几种模式对比 |模式|props 写法|数据来源|适用场景| |--|--|--|--| |对象模式|props: { key: value }|静态对象|固定配置、开关、默认值| |布尔模式|props: true|将 $route.params 作为 props|路由参数(如 /user/:id)| |函数模式|props: (route) => ({ ... })|动态计算,可访问 route|需要加工参数或合并静态数据|
扫一扫手机看
点击排行
windows 文件资源管理器使用
Layui 弹窗open使用说明
SQL Server 中字符串函数使用
C# 使用QQ邮箱代理做邮件接收功能
SQL Server关于apply的两种形式cross apply 和 outer apply
ASP.NET MVC 模型的自定义验证
nvm安装及常用命令
SQL Server 中数据类型转换
SQL Server 中WITH AS短语的使用
IE浏览器下AJAX缓存问题导致数据不更新的解决办法
订阅号