Javaweb - 14.5 Vue3 路由机制
目录
路由简介
路由入门案例
编程式路由(useRouter)
路由传参(useRoute)
路由守卫
案例测试
完!
路由简介
什么是路由:
定义:路由就是根据不同的 URL 地址展示不同的内容或页面
作用:
SPA 中,可以实现不同视图之间的无刷新切换
实现页面认证和权限控制
路由入门案例
案例需求:
创建项目和导入路由依赖:
npm create vite@4
npm install
npm install vue-router@4 --save
准备页面组件
单独在 src 文件夹下面创建一个 routers 文件夹,里面存放 router.js
// 导入创建路由对象需要的函数
import {createRouter,createWebHashHistory} from 'vue-router'// 导入 .vue 组件
import Home from '../comments/Home.vue'
import List from '../comments/List.vue'
import Add from '../comments/Add.vue'
import Update from '../comments/Update.vue'// 创建一个路由对象
const router = createRouter({// history 属性用于记录路由的历史history:createWebHashHistory(),// routes 用于定义多个不同的路径和组件之间的对应关系routes:[{path:'/home',component:Home},{path:'/list',component:List},{path:'/add',component:Add},{path:'/update',component:Update},{path:'/',component:Home}]
})// 向外暴露
export default rouer
配置 main.js 文件:
import { createApp } from 'vue'import App from './App.vue'
// 在整个 App.vue 中可以使用路由
import router from './routers/router.js'const app = createApp(App)
// 绑定路由对象
app.use(router)
// 挂载视图
app.mount('#app')
App.vue 的页面
<script setup>
</script><template><div>App 开头的内容 <br><router-link to = "/Home">Home页</router-link><br><router-link to = "/List">List页</router-link><br><router-link to = "/Add">Add页</router-link><br><router-link to = "/Update">Update页</router-link><br><hr><!-- router-view 标签会背替换成具体的 .vue --><router-view></router-view><hr>App 结束的内容</div>
</template><style scoped></style>
这样,就基础的实现了我们的需求:
我们还可以在不同的页面中进行相互跳转:
例如,在 Home 页中同样加一个 router-link 标签,实现从 Home 页向 Add 页的跳转:
<script setup>
</script><template><div><router-link to="/add">Add页</router-link><h1> Home 页面</h1></div>
</template><style scoped></style>
也可以实现重定向,比如当我们的路径为 /showAll 的时候,重定向到 /list:
先在 router.js 中的 router 对象中,配置 path 和对应的 redirect
然后在 App.vue 中添加 router-link 的标签即可
编程式路由(useRouter)
声明式路由:
<router-link to = "/list">list页</router-link> 这种路由,点击后只能切换 /list 对应的组件,是固定的
编程式路由:
通过 useRouter,动态决定向那个组件切换的路由
这里的 useRouter 方法返回的是一个 router 对象,可以用它来做,如导航到新页面,返回上一面等操作
<script setup>import {useRouter} from 'vue-router'import {ref} from 'vue'let myPath = ref('')const router = useRouter()function showList() {// 编程式路由实现页面跳转// 方式一:router.push("/list")router.push({path:"/list"})}function goMyPage() {router.push(myPath.value)}
</script><template><div><!-- 声明式路由 --><router-link to="/home">home</router-link><br><router-link to="/list">list</router-link><br><router-link to="/add">add</router-link><br><router-link to="/update">update</router-link><br><!-- 编程式路由 --><button @click="showList()">list</button><br><button @click="goMyPage()">Go</button><input type = "text" v-model="myPath"><router-view></router-view></div>
</template><style scoped></style>
路由传参(useRoute)
路径参数:
在路径中使用一个动态字段来实现,我们称之为路径参数。
例如:查看数据详情 /showDetail/1, 1 就是要查看详情的 id,可以动态填值。
键值对参数:
类似与 get 请求通过 URL 传参,数据是键值对形式的。
例如:查看数据详情 /showDetail?hid=1,hid 就是要传递的键值对参数。
读取参数:
在 Vue3 和 Vue Router4 中,我们可以使用 useRoute 这个函数,从 Vue 的组合式 API 中获取路由对象。
useRoute 方法返回的是当前的 route 对象,我们可以用它来获取关于当前路由的信息,如当前的路径,键值对参数等。
案例需求:切换到 ShowDetail.vue 组件时,向该组件通过路由传递参数
1.路径参数:{声明式路由和编程式路由}
准备一个 ShowDetail.vue 页面:
<script setup></script><template><div><h1>ShowDetail接收路径参数</h1></div>
</template><style scoped></style>
在 router.js 中进行配置:
// 导入创建路由的相关方法
import { createRouter, createWebHashHistory } from "vue-router";// 导入 .vue 组件
import Home from '../components/Home.vue'
import Add from '../components/Add.vue'
import List from '../components/List.vue'
import Update from '../components/Update.vue'
import ShowDetail from '../components/ShowDetail.vue'const router = createRouter({history:createWebHashHistory(),routes:[{path:"/showDetail/:id/:language",component:ShowDetail},{path:"/",component:Home,},{path:"/home",component:Home,},{path:"/list",component:List,},{path:"/add",component:Add,},{path:"/update",component:Update}]
})
export default router
ShowDetail.vue:
<script setup>
/*** 接收传递过来的路径参数* useRoute 函数是用来接收参数的*/import {useRoute} from 'vue-router'import {ref,onUpdated} from 'vue'let languageId = ref(0)let languageName = ref("")let route = useRoute()languageId.value=route.params.idlanguageName.value=route.params.language// 让页面可以实时更新~onUpdated(()=>{languageId.value=route.params.idlanguageName.value=route.params.language})
</script><template><div><h1>ShowDetail接收路径参数</h1><h3>{{languageId}}{{languageName}}是世界上最好的语言</h3></div>
</template><style scoped></style>
App.vue:
<script setup>import {useRouter} from 'vue-router'import {ref} from 'vue'const router = useRouter()function showDetail(id,language){router.push(`/showDetail/${id}/${language}`)}
</script><template><div><router-link to="/showDetail/1/java">声明式路由路径传参</router-link><button @click="showDetail(2,'PHP')">编程式路由路径传参</button><hr><router-view></router-view></div>
</template><style scoped></style>
2. 键值对参数{声明式路由和编程式路由}
router.js:
// 导入创建路由的相关方法
import { createRouter, createWebHashHistory } from "vue-router";// 导入 .vue 组件
import Home from '../components/Home.vue'
import Add from '../components/Add.vue'
import List from '../components/List.vue'
import Update from '../components/Update.vue'
import ShowDetail from '../components/ShowDetail.vue'
import ShowDetail2 from '../components/showDetail2.vue'
const router = createRouter({history:createWebHashHistory(),routes:[{path:"/showDetail2",component:ShowDetail2},{path:"/showDetail/:id/:language",component:ShowDetail},{path:"/",component:Home,},{path:"/home",component:Home,},{path:"/list",component:List,},{path:"/add",component:Add,},{path:"/update",component:Update}]
})
export default router
ShowDetail2:
<script setup>
/*** 接收传递过来的路径参数* useRoute 函数是用来接收参数的*/import {useRoute} from 'vue-router'import {ref,onUpdated} from 'vue'let languageId = ref(0)let languageName = ref("")let route = useRoute()languageId.value=route.query.idlanguageName.value=route.query.languageonUpdated(()=>{languageId.value=route.query.idlanguageName.value=route.query.language})
</script><template><div><h1>ShowDetail2接收键值对参数</h1><h3>{{languageId}}{{languageName}}是世界上最好的语言</h3></div>
</template><style scoped></style>
App.vue:
<script setup>import {useRouter} from 'vue-router'import {ref} from 'vue'const router = useRouter()function showDetail(id,language){router.push(`/showDetail/${id}/${language}`)}function showDetail2(id,language){router.push(`/showDetail2?id=${id}&language=${language}`)}
</script><template><div><router-link to ="/showDetail2?id=1&language=java">声明式路由键值对传参</router-link><button @click="showDetail2(2,'PHP')">编程式路由键值对传参</button><hr><router-view></router-view></div>
</template><style scoped></style>
路由守卫
在 Vue3 中,路由首位是用于在路由切换期间,进行一些特定任务的回调函数。路由守卫可以用于许多任务:例如验证用户是否已经登录,在路由切换前提供确认提示,请求数据等。
全局前置守卫:在路由切换前被调用,可以用于验证用户是否已登录,中断导航,请求数据等。
全局后置首位:在路由切换之后被调用,可以用于处理数据,操作 DOM,记录日志等
守卫代码的位置:在 router.js 文件中
// 设置全局前置首位
// 每次路由切换页面前,都会执行 beforeEach 中的回调函数
router.beforeEach((to,from,next)=>{/*** from 上一个页面 表示从哪里来* to 下一个页面 表示到哪里去* next 放行的方法,只有执行了该方法,才会放行路由 类似与过滤器中的 filterChain.doFilter* next() 放行* next("/路径") 路由的重定向,可以转发到其他地址* 但是到达目标组件前会在此经过前置路由守卫,需要注意判断,避免无限重定向* * */console.log("beforeEach")console.log(from.path)console.log(to.path)next()}
)
// 设置全局后置路由
// 每次路由切换页面后,都会执行 afterEach 中的回调函数
router.afterEach(()=>{console.log("afterEach")}
)
案例测试
要求:登录案例,登录以后才可以进入 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)} 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 {useRouter, useRoute} from 'vue-router'let route = useRoute()let router = useRouter()let username = window.localStorage.getItem('username')let logout = () => {//清楚 localStorge 中的 usernamewindow.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></script><template><div><router-view></router-view></div>
</template><style scoped>
</style>
定义 routers.js:
import { createRouter, createWebHashHistory } from "vue-router";
import Home from "../components/Home.vue";
import Login from "../components/Login.vue";const router = createRouter({history: createWebHashHistory(),routes: [{path: "/home",component: Home,},{path:"/",component:Home},{path:"/login",component:Login}],
});// 设置路由的全局前置首位
router.beforeEach((to,from,next) => {console.log(`从哪里来:${from.path},到哪里去${to.path}`)if (to.path == '/login') {next()} else {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
修改 main.js
import { createApp } from 'vue'
import App from './App.vue'import router from './routers/router'
let app = createApp(App)
app.use(router)
app.mount('#app')
测试无误~
补充:
路由传参:useRoute,编程式路由:useRouter: