7.4 编程式路由(useRouter)
普通路由
<router-link to="/list">list页</router-link>
这种路由,to中的内容目前是固定的,点击后只能切换/list对象组件(声明式路由)
编程式路由
- 通过useRouter,动态决定向那个组件切换的路由
- 在 Vue 3 和 Vue Router 4 中,你可以使用
useRouter
来实现动态路由(编程式路由)
- 这里的
useRouter
方法返回的是一个 router 对象,你可以用它来做如导航到新页面、返回上一页面等操作。
案例需求: 通过普通按钮配合事件绑定实现路由页面跳转,不直接使用router-link标签
- App.vue
<script setup type="module"> import {useRouter} from 'vue-router' import {ref} from 'vue' //创建动态路由对象 let router = useRouter() let routePath =ref('') let showList= ()=>{ // 编程式路由 // 直接push一个路径 //router.push('/list') // push一个带有path属性的对象 router.push({path:'/list'}) } </script> <template> <div> <h1>App页面</h1> <hr/> <!-- 路由的连接 --> <router-link to="/">home页</router-link> <br> <router-link to="/list">list页</router-link> <br> <router-link to="/showAll">showAll页</router-link> <br> <router-link to="/add">add页</router-link> <br> <router-link to="/update">update页</router-link> <br> <!-- 动态输入路径,点击按钮,触发单击事件的函数,在函数中通过编程是路由切换页面 --> <button @click="showList()">showList</button> <br> <hr/> <!-- 路由连接对应视图的展示位置 --> <hr> 默认展示位置:<router-view></router-view> <hr> Home视图展示:<router-view name="homeView"></router-view> <hr> List视图展示:<router-view name="listView"></router-view> <hr> Add视图展示:<router-view name="addView"></router-view> <hr> Update视图展示:<router-view name="updateView"></router-view> </div> </template> <style scoped> </style>
7.5 路由传参(useRoute)
路径参数
- 在路径中使用一个动态字段来实现,我们称之为路径参数
- 例如: 查看数据详情
/showDetail/1
,1
就是要查看详情的id,可以动态添值!
键值对参数
- 类似与get请求通过url传参,数据是键值对形式的
- 例如: 查看数据详情
/showDetail?hid=1
,hid=1
就是要传递的键值对参数
- 在 Vue 3 和 Vue Router 4 中,你可以使用
useRoute
这个函数从 Vue 的组合式 API 中获取路由对象。 useRoute
方法返回的是当前的 route 对象,你可以用它来获取关于当前路由的信息,如当前的路径、查询参数等。
案例需求 : 切换到ShowDetail.vue组件时,向该组件通过路由传递参数
- 修改App.vue文件
<script setup type="module"> import {useRouter} from 'vue-router' //创建动态路由对象 let router = useRouter() //动态路由路径传参方法 let showDetail= (id,language)=>{ // 尝试使用拼接字符串方式传递路径参数 //router.push(`showDetail/${id}/${languange}`) /*路径参数,需要使用params */ router.push({name:"showDetail",params:{id:id,language:language}}) } let showDetail2= (id,language)=>{ /*uri键值对参数,需要使用query */ router.push({path:"/showDetail2",query:{id:id,language:language}}) } </script> <template> <div> <h1>App页面</h1> <hr/> <!-- 路径参数 --> <router-link to="/showDetail/1/JAVA">showDetail路径传参显示JAVA</router-link> <button @click="showDetail(1,'JAVA')">showDetail动态路由路径传参显示JAVA</button> <hr/> <!-- 键值对参数 --> <router-link v-bind:to="{path:'/showDetail2',query:{id:1,language:'Java'}}">showDetail2键值对传参显示JAVA</router-link> <button @click="showDetail2(1,'JAVA')">showDetail2动态路由键值对传参显示JAVA</button> <hr> showDetail视图展示:<router-view name="showDetailView"></router-view> <hr> showDetail2视图展示:<router-view name="showDetailView2"></router-view> </div> </template> <style scoped> </style>
- 修改router.js增加路径参数占位符
// 导入路由创建的相关方法 import {createRouter,createWebHashHistory} from 'vue-router' // 导入vue组件 import ShowDetail from '../components/ShowDetail.vue' import ShowDetail2 from '../components/ShowDetail2.vue' // 创建路由对象,声明路由规则 const router = createRouter({ history: createWebHashHistory(), routes:[ { /* 此处:id :language作为路径的占位符 */ path:'/showDetail/:id/:language', /* 动态路由传参时,根据该名字找到该路由 */ name:'showDetail', components:{ showDetailView:ShowDetail } }, { path:'/showDetail2', components:{ showDetailView2:ShowDetail2 } }, ] }) // 对外暴露路由对象 export default router;
- ShowDetail.vue 通过useRoute获取路径参数
<script setup type="module"> import{useRoute} from 'vue-router' import { onUpdated,ref } from 'vue'; // 获取当前的route对象 let route =useRoute() let languageId = ref(0) let languageName = ref('') // 借助更新时生命周期,将数据更新进入响应式对象 onUpdated (()=>{ // 获取对象中的参数 languageId.value=route.params.id languageName.value=route.params.language console.log(languageId.value) console.log(languageName.value) }) </script> <template> <div> <h1>ShowDetail页面</h1> <h3>编号{{route.params.id}}:{{route.params.language}}是世界上最好的语言</h3> <h3>编号{{languageId}}:{{languageName}}是世界上最好的语言</h3> </div> </template> <style scoped> </style>
- ShowDetail2.vue通过useRoute获取键值对参数
<script setup type="module"> import{useRoute} from 'vue-router' import { onUpdated,ref } from 'vue'; // 获取当前的route对象 let route =useRoute() let languageId = ref(0) let languageName = ref('') // 借助更新时生命周期,将数据更新进入响应式对象 onUpdated (()=>{ // 获取对象中的参数(通过query获取参数,此时参数是key-value形式的) console.log(route.query) console.log(languageId.value) console.log(languageName.value) languageId.value=route.query.id languageName.value=route.query.language }) </script> <template> <div> <h1>ShowDetail2页面</h1> <h3>编号{{route.query.id}}:{{route.query.language}}是世界上最好的语言</h3> <h3>编号{{languageId}}:{{languageName}}是世界上最好的语言</h3> </div> </template> <style scoped> </style>
7.6 路由守卫
在 Vue 3 中,路由守卫是用于在路由切换期间进行一些特定任务的回调函数。路由守卫可以用于许多任务,例如验证用户是否已登录、在路由切换前提供确认提示、请求数据等。Vue 3 为路由守卫提供了全面的支持,并提供了以下几种类型的路由守卫:
- 全局前置守卫:在路由切换前被调用,可以用于验证用户是否已登录、中断导航、请求数据等。
- 全局后置守卫:在路由切换之后被调用,可以用于处理数据、操作 DOM 、记录日志等。
- 守卫代码的位置: 在router.js中
//全局前置路由守卫 router.beforeEach( (to,from,next) => { //to 是目标地包装对象 .path属性可以获取地址 //from 是来源地包装对象 .path属性可以获取地址 //next是方法,不调用默认拦截! next() 放行,直接到达目标组件 //next('/地址')可以转发到其他地址,到达目标组件前会再次经过前置路由守卫 console.log(to.path,from.path,next) //需要判断,注意避免无限重定向 if(to.path == '/index'){ next() }else{ next('/index') } } ) //全局后置路由守卫 router.afterEach((to, from) => { console.log(`Navigate from ${from.path} to ${to.path}`); });
登录案例,登录以后才可以进入home,否则必须进入login
- 定义Login.vue
<script setup> import {ref} from 'vue' import {useRouter} from 'vue-router' let username =ref('') let password =ref('') let router = useRouter(); let login = () =>{ console.log(username.value,password.value) if(username.value == 'root' & password.value == '123456'){ router.push({path:'/home',query:{'username':username.value}}) //登录成功利用前端存储机制,存储账号! localStorage.setItem('username',username.value) //sessionStorage.setItem('username',username) }else{ alert('登录失败,账号或者密码错误!'); } } </script> <template> <div> 账号: <input type="text" v-model="username" placeholder="请输入账号!"><br> 密码: <input type="password" v-model="password" placeholder="请输入密码!"><br> <button @click="login()">登录</button> </div> </template> <style scoped> </style>
- 定义Home.vue
<script setup> import {ref} from 'vue' import {useRoute,useRouter} from 'vue-router' let route =useRoute() let router = useRouter() // 并不是每次进入home页时,都有用户名参数传入 //let username = route.query.username let username =window.localStorage.getItem('username'); let logout= ()=>{ // 清除localStorge中的username //window.sessionStorage.removeItem('username') window.localStorage.removeItem('username') // 动态路由到登录页 router.push("/login") } </script> <template> <div> <h1>Home页面</h1> <h3>欢迎{{username}}登录</h3> <button @click="logout">退出登录</button> </div> </template> <style scoped> </style>
- App.vue
<script setup type="module"> </script> <template> <div> <router-view></router-view> </div> </template> <style scoped> </style>
- 定义routers.js
// 导入路由创建的相关方法 import {createRouter,createWebHashHistory} from 'vue-router' // 导入vue组件 import Home from '../components/Home.vue' import Login from '../components/login.vue' // 创建路由对象,声明路由规则 const router = createRouter({ history: createWebHashHistory(), routes:[ { path:'/home', component:Home }, { path:'/', redirect:"/home" }, { path:'/login', component:Login }, ] }) // 设置路由的全局前置守卫 router.beforeEach((to,from,next)=>{ /* to 要去那 from 从哪里来 next 放行路由时需要调用的方法,不调用则不放行 */ console.log(`从哪里来:${from.path},到哪里去:${to.path}`) if(to.path == '/login'){ //放行路由 注意放行不要形成循环 next() }else{ //let username =window.sessionStorage.getItem('username'); let username =window.localStorage.getItem('username'); if(null != username){ next() }else{ next('/login') } } }) // 设置路由的全局后置守卫 router.afterEach((to,from)=>{ console.log(`从哪里来:${from.path},到哪里去:${to.path}`) }) // 对外暴露路由对象 export default router;
- 启动测试
npm run dev