vue3通信大全(一)—— 组件通信与provide - 掘金 (juejin.cn)
vue3通信大全(三)—— 全局状态管理库pinia,vuex - 掘金 (juejin.cn)
vue3通信大全(四)—— Slot /浏览器储存/window - 掘金 (juejin.cn)
前言
在 Vue 3 中,除了传统的组件间通信方式(如 props 下传、事件上冒泡、Vuex 等),我们还可以利用路由来实现不同组件间的通信。下面我将详细介绍如何在 Vue 3 中使用路由传参以及一些相关的实践。
Params作为参数
Params
参数是通过路径的一部分来传递的,通常用于表示动态的部分,例如 /users/:userId
中的 :userId
就是一个 param
参数。
使用方法:定义路由:
在 Vue Router 中定义带有 params
的路由非常简单,只需要在路径中使用占位符即可:
index.js
文件中:
import { createWebHistory,createRouter } from "vue-router";
const routes = [{
path: "/parent",
name: "parent",
component: () => import("@/components/demo2/parent.vue"),
},
{
path: "/child/:id", //传递的参数
name: "child", // 命名路由
component: () => import("@/components/demo2/child.vue"),
}];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;
当前页:
<template>
<h1>
父组件
</h1>
<button @click="goSon">点击跳转</button>
</template>
<script setup>
import {useRouter} from 'vue-router'
const router = useRouter()
const goSon=()=>{
router.push({name:'child',params:{id: '123123'}})
}
</script>
目标页:
<template>
son: route.params = {{ route.params.id }}
</template>
<script setup>
import {useRoute}from 'vue-router'
const route = useRoute() //使用useRoute获取当前页面信息
</script>
当用户访问类似 /child/123
这样的 URL 时,:idd
的值会被自动提取出来,并且可以在这个组件中通过 route.params.id
获取到。而当我们如果需要从一个组件导航到另一个带有参数的路由,可以使用 router.push
方法,并且提供参数的值,从而实现传值。
Query 参数
Query
参数则是通过 URL 中的查询字符串来传递的,通常用于过滤、排序或者传递额外的信息,例如 /users?name=John
中的 name=John
就是一个 query
参数。
index
文件:
import { createWebHistory,createRouter } from "vue-router";
const routes = [{
path: "/parent",
component: () => import("@/components/demo2/parent.vue"),
},
{
path: "/child", //query传值不需要使用name和修改path格式
component: () => import("@/components/demo2/child.vue"),
}];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;
当前页:
<template>
<h1>
父组件
</h1>
<button @click="goSon">点击跳转</button>
</template>
<script setup>
import {useRouter} from 'vue-router'
const router = useRouter()
const goSon=()=>{
router.push({path:'/child',query:{id: '123123'}})
}
</script>
目标页:
<template>
son: route.query.id = {{ route.query.id }}
</template>
<script setup>
import {useRoute}from 'vue-router'
const route = useRoute()
</script>
使用query传参时,不需要我们在路由文件中修改目标页面的path路径而格式,而是在当前页面使用router.push(path:'xxx',query:{键名:键值})
,在跳转到目标页面后,目标页面的url会在后面加上xxx?键名=键值
。而在目标页面要取到这个值,也是使用useRoute
获取到当前页面信息使用route.query.id
得到对应的query。
teleport
使用 Teleport
组件的主要目的是为了能够将一个组件渲染到 DOM 树中的另一个位置,而不是直接在其父组件的 DOM 子树内。这在处理模态框、弹窗等需要跨越多个组件层级的 UI 元素时特别有用。
非常好的例子就是登录弹窗的动态使用Teleport
来实现的,如果我们使用的是登入弹窗,那么不论在哪个页面,这个弹窗框的层级应该是最高的,同时应该脱离文档流不影响其下面的结构。我们在HTML中会使用Z-index属性,但是在vue组件化结构中是不生效的,因此Teleport
便孕育而生。
index.html
文件:
<div id="app">
<!-- 应用的主要内容 -->
<App></App>
</div>
<!-- Teleport 的目标容器 -->
<div id="login-container"></div>
App.vue
文件:
<template>
<div>
<button @click="showLogin = true">Login</button>
这是之外的数据
<teleport v-if="showLogin" to="#login-container">
<div class="login-modal">
<h1>登入</h1>
<input type="text" placeholder="Username" v-model="username">
<input type="password" placeholder="Password" v-model="password">
<button @click="submitLogin">提交</button>
</div>
</teleport>
</div>
</template>
<script setup>
import{ref}from 'vue'
const showLogin=ref(false)
const username=ref('')
const password=ref('')
const submitLogin=()=>{
//登入逻辑
showLogin.value = false; // Close the modal
}
</script>
这里我们明显看到登入框弹出时,taleport并没有挤压其他的DOM结构。
为什么需要在#app内再放一个<App />
?
- 分离关注点:
<App>
元素允许我们在 HTML 文件中定义应用程序的主要内容区域,而main.js
中的app.mount('#app')
则负责将 Vue 组件挂载到这个区域。
- 保持 HTML 结构清晰:
- 通过在 HTML 中定义
<App>
,我们可以保留 HTML 文件的基本结构,使其易于阅读和维护。
- 通过在 HTML 中定义
换句话说我们也可以在#app
内再放一个<App />
但是这样做使得我们的登入的DOM结构不再清晰,这时不被优秀的程序设计所接受的。