路由简介
路由
就是根据不同的 URL 地址
展示不同的内容或页面
。
- 单页应用程序(SPA)中,路由可以实现不同视图之间的
无刷新切换,提升用户体验
;- 路由还可以实现
页面的认证和权限控制,保护用户的隐私和安全
;- 路由还可以利用浏览器的前进与后退,帮助用户更好地访问
历史页面
。
路由入门案例
【案例:启动程序,进入首页,点击首页和列表可以自由切换】
1、创建项目安装依赖(含路由依赖)
npm create vite
//创建项目,cd 项目文件夹
//进入项目文件夹npm install
或npm i
//安装项目需求依赖npm install vue-router
或npm install vue-router@4 --save
// 安装vue-router
2、创建页面和组件
router-view
:该标签会被替换成具体的.vue
对象, 一个视图上可以同时存在多个router-view
,每个router-view
可以设置成展示哪个组件
App.vue
<script setup></script>
<template>
<div>
<!-- 父组件跳转到不同页面 -->
<h2>1、父组件 App.vue 跳转到不同页面按钮</h2>
<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 />
此页面当前部分内容【不会随着下面路由内容的改变而改变】
<hr />
<!-- 该标签会被切换成具体的.vue文件
一个视图上可以同时存在多个router-view,每个router-view可以设置成展示哪个组件
一般来说,实际场景中一个.vue中用一个router-view标签就可以解决99%的业务需求,此处了解即可;
-->
<router-view></router-view>
<hr />
此页面当前部分内容【不会随着下面路由内容的改变而改变】
<hr />
</div>
</template>
<style scoped></style>
Home.vue
<script setup></script>
<template>
<div>
<h2>2、兄弟组件界面之间的跳转</h2>
<router-link to="/list">Home页面跳转List页面</router-link><br />
<h1>Home页面</h1>
</div>
</template>
<style scoped></style>
Add.vue
<script setup></script>
<template>
<div>
<h2>2、兄弟组件界面之间的跳转</h2>
<router-link to="/update">Add页面跳转Update页面</router-link><br />
<h1>Add页面</h1>
</div>
</template>
<style scoped></style>
List.vue
<script setup></script>
<template>
<div>
<h2>2、兄弟组件界面之间的跳转</h2>
<router-link to="/add">List页面跳转Add页面</router-link><br />
<h1>List页面</h1>
</div>
</template>
<style scoped></style>
Update.vue
<script setup></script>
<template>
<div>
<h2>2、兄弟组件界面之间的跳转</h2>
<router-link to="/home">Update页面跳转Home页面</router-link><br />
<h1>Update页面</h1>
</div>
</template>
<style scoped></style>
3、准备路由配置
- 1.
导入路由创建的相关方法
import { createRouter, createWebHashHistory } from "vue-router";
- 2.
创建路由对象,声明路由规则
使用 createRouter(),该方法有两个属性:history 用于记录路由的历史; routes:用于定义多个不同路径和组件之间的对应关系
- 3.
对外暴露路由对象
export default router;;
- 4.
导入创建的add、list等.vue组件
router.js
//导入路由创建的相关方法
import { createRouter, createWebHashHistory } from "vue-router";
/* 导入.vue组件 */
import Home from "../components/Home.vue";
import List from "../components/List.vue";
import Add from "../components/Add.vue";
import Update from "../components/Update.vue";
//创建路由对象,声明路由规则
const router = createRouter({
//history 用于记录路由的历史
history: createWebHashHistory(),
//routes:用于定义多个不同路径和组件之间的对应关系
routes: [
{
path: "/",
component: Home,
},
{
path: "/home",
component: Home,
},
{
path: "/list",
component: List,
},
{
path: "/add",
component: Add,
},
{
path: "/update",
component: Update,
},
],
});
//对外暴露路由对象
export default router;
4、main.js引入router配置
- 在整个App.vue中可以使用路由:
import router from "./routers/router.js"
;
const app = createApp(App);
app.use(router);
app.mount("#app");
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");
5、启动测试
路由router入门案例演示
路由重定向
直接在路由的创建方法中使用
redirect
即可;
在页面访问otherAll
时,会重定向到list
页面
编程式路由(useRouter)
普通声明式路由
:
<router-link to="/list">list页</router-link>
这种路由,to
中的内容目前是固定的
,点击后只能切换/list对象组件
编程式路由(useRouter)
:
useRouter
方法返回的是一个router
对象,通过useRouter
,来实现动态路由(编程式路由)
注意 编程式路由 不是 动态路由
,
案例需求: 通过普通按钮配合事件绑定实现路由页面跳转,不直接使用router-link标签
上面案例代码不变,直接在App.vue
引入useRouter
即可,代码如下:
App.vue
<script setup>
/* 导入useRouter 方法,useRouter 方法返回的是一个 router 对象,你可以用它来做如导航到新页面、返回上一页面等操作 */
import { useRouter } from "vue-router";
/* 导入ref存储页面逻辑代码 */
import { ref } from "vue";
//创建动态路由对象
const router = useRouter();
let routePath = ref("");
function goMyPage() {
//编程式路由实现页面跳转
router.push(routePath.value);
}
</script>
<template>
<div>
<!-- 父组件跳转到不同页面 -->
<h1 style="color:red">Ⅰ、声明式路由:1、父组件 App.vue 跳转到不同页面按钮</h1>
<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 />
此页面当前部分内容【不会随着下面路由内容的改变而改变】
<hr />
<!-- 该标签会被切换成具体的.vue文件
一个视图上可以同时存在多个router-view,每个router-view可以设置成展示哪个组件
一般来说,实际场景中一个.vue中用一个router-view标签就可以解决99%的业务需求,此处了解即可;
-->
<router-view></router-view>
<hr />
此页面当前部分内容【不会随着下面路由内容的改变而改变】
<hr />
<!-- 2、编程式路由 -->
<h1 style="color:red">Ⅱ、编程式路由</h1>
<br />
<!-- v-model="routePath" 响应式数据的双向绑定,来绑定一个路径 -->
<button @click="goMyPage()">GO</button><input type="text" v-model="routePath" />
<hr />
</div>
</template>
<style scoped></style>
演示过程:
编程式路由
路由传参
App.vue
<script setup>
/* 导入useRouter 方法,useRouter 方法返回的是一个 router 对象,你可以用它来做如导航到新页面、返回上一页面等操作 */
import { useRouter } from "vue-router";
/* 导入ref存储页面逻辑代码 */
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="/showDetail/1/北京">声明式路由路径传参</router-link>
<hr />
<button @click="showDetail(2, '春天')">编程式路由传参</button>
<br />
<br />
<hr />
<hr />
<hr />
<br />
<router-link to="/showDetail2?id=3&language=夏天 ">声明式路由键值对传参</router-link>
<hr />
<button @click="showDetail2(4, '伊春')">编程式键值对传参</button>
<hr />
<router-view></router-view>
</div>
</template>
<style scoped></style>
ShowDetail.vue
<script setup>
/* 注意:下面引入的userRoute方法是用来接收传递过来的路径参数的,
而之前 import {useRouter} from 'vue-router' 中的userRouter是用来做编程式路由的 */
import { useRoute } from "vue-router";
//响应式数据
//导入生命周期的方法
import { ref, onUpdated } from "vue";
let languageId = ref(0);
let languageName = ref("");
/* 获取当前的route对象
route.param:表示路径参数
route.query:表示键值对参数
*/
let route = useRoute();
languageId.value = route.params.id;
languageName.value = route.params.language;
/* 如果同一个界面【如App.vue中设置两种传参方式:1、声明式路由路径传参2、编程式路由方式】
设置两种传参方式,会出现下述问题:点击其中一个方式传参接收成功后,第二个传参接收失败的问题,
此时要借用Vue生命周期中的onUpdated方法来进行处理,当接收参数成功后,再重新赋值即可。
使用方法,导入生命周期的方法,重新赋值🆗!
*/
//onUpdated方法中重新赋值
onUpdated(() => {
languageId.value = route.params.id;
languageName.value = route.params.language;
});
</script>
<template>
<div>
<h1>ShowDetail1 路径传参</h1>
<h2>{{ languageId }}、{{ languageName }}非常棒!</h2>
</div>
</template>
<style scoped></style>
ShowDetail2.vue
<script setup>
/* 注意:下面引入的userRoute方法是用来接收传递过来的路径参数的,
而之前 import {useRouter} from 'vue-router' 中的userRouter是用来做编程式路由的 */
import { useRoute } from "vue-router";
//响应式数据
//导入生命周期的方法
import { ref, onUpdated } from "vue";
let languageId = ref(0);
let languageName = ref("");
/* 获取当前的route对象
route.param:表示路径参数
route.query:表示键值对参数
*/
let route = useRoute();
// languageId.value = route.params.id;
// languageName.value = route.params.language;
/* 如果同一个界面【如App.vue中设置两种传参方式:1、声明式路由路径传参2、编程式路由方式】
设置两种传参方式,会出现下述问题:点击其中一个方式传参接收成功后,第二个传参接收失败的问题,
此时要借用Vue生命周期中的onUpdated方法来进行处理,当接收参数成功后,再重新赋值即可。
使用方法,导入生命周期的方法,重新赋值🆗!
*/
//onUpdated方法中重新赋值
// onUpdated(() => {
// languageId.value = route.params.id;
// languageName.value = route.params.language;
// });
//键值对传参
languageId.value = route.query.id;
languageName.value = route.query.language;
//onUpdated方法中重新赋值
onUpdated(() => {
languageId.value = route.query.id;
languageName.value = route.query.language;
});
</script>
<template>
<div>
<h1>ShowDetail2 键值对传参</h1>
<h2>{{ languageId }}、{{ languageName }}非常美丽!</h2>
</div>
</template>
<style scoped></style>
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");
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 用于记录路由的历史
history: createWebHashHistory(),
//routes:用于定义多个不同路径和组件之间的对应关系
routes: [
{ path: "/showDetail2", component: ShowDetail2 },
/* "/showDetail/:id/:language"中的:id/:language就不是地址了,代表App.vue中
<router-link to="/showDetail/1/java">声明式路由路径传参</router-link>
路径中携带的参数 */
{ path: "/showDetail/:id/:language", component: ShowDetail },
],
});
//对外暴露路由对象
export default router;
演示过程:
路由传参
路由守卫
在 Vue 3 中,路由守卫是用于在路由切换期间进行一些特定任务的回调函数。路由守卫可以用于许多任务,例如
验证用户是否已登录、在路由切换前提供确认提示、请求数据
等。Vue 3 为路由守卫提供了全面的支持,并提供了以下几种类型的路由守卫:
1. 全局前置守卫
:在路由切换前被调用,可以用于验证用户是否已登录、中断导航、请求数据等。2. 全局后置守卫
:在路由切换之后被调用,可以用于处理数据、操作 DOM 、记录日志等。3. 守卫代码的位置
: 在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
规定
:如果是root
用户并且密码是123456
则登录成功
创建项目略,代码如下
:
App.vue
<script setup></script>
<template>
<div>
<router-view></router-view>
</div>
</template>
<style scoped></style>
main.js
import { createApp } from "vue";
import App from "./App.vue";
//导入router路由对象
import router from "./routers/router";
//给app对象使用router对象,然后挂载到app上
const app = createApp(App);
app.use(router);
app.mount("#app");
Home.vue
<script setup>
let username = window.sessionStorage.getItem("username");
//导入响应式路由对象
import { useRouter } from "vue-router";
//创建对象
const router = useRouter();
function logout() {
//1、先清除缓存
window.sessionStorage.removeItem("username");
//2、使用路由重定向到登录界面
router.push("/login");
}
</script>
<template>
<div>
<h1>Home页面</h1>
<h2>欢迎 {{ username }} 登录</h2>
<button @click="logout()">退出登录</button>
</div>
</template>
<style scoped></style>
Login.vue
<script setup>
//导入处理响应式数据的ref函数
import { ref } from "vue";
//路由跳转,usrRouter用来做编程式路由
import { useRouter } from "vue-router";
let router = useRouter();
/*
双向绑定
双向绑定: 响应式数据的变化会更新dom树,但是dom树上用户的操作造成的数据改变会同步更新到响应式数据
- 用户通过表单标签才能够输入数据,所以双向绑定都是应用到表单标签上的,其他标签不行
- v-model专门用于双向绑定表单标签的value属性,语法为 v-model:value='',可以简写为 v-model=''
- v-model还可以用于各种不同类型的输入,<textarea>、<select> 元素。
*/
let username = ref("");
let password = ref("");
//登录方法
function login() {
//获取用户名和密码,校验,如果是root用户并且密码是123456则登录成功
//登录成功后跳转到/home页面
//登录失败,不跳转,直接给出提示
if (username.value == "root" && password.value == "123456") {
//将用户名保存在浏览器上,使用sessionStorage 或 localStorage
//可以参考BOM编程对象结构:window 顶级对象代表整个浏览器窗口
//- localStorage对象 window对象的属性之一,代表浏览器的本地数据持久化存储,在浏览器中存储 key/value 对。没有过期时间。
//- sessionStorage对象 window对象的属性之一,代表浏览器的本地数据会话级存储,在浏览器中存储 key/value 对。 在关闭窗口或标签页之后将会删除这些数据。
window.sessionStorage.setItem("username", username.value);
//路由跳转
router.push("/home");
} else {
alert("用户名或密码错误/(ㄒoㄒ)/~~,请尝试重新登录(*^_^*)!");
}
}
</script>
<template>
<div>
<h1>Longin页面</h1>
账号:<input type="text" v-model="username" /><br />
密码:<input type="password" v-model="password" /><br />
<button @click="login()">登录</button>
</div>
</template>
<style scoped></style>
router.js
//导入创建路由对象的方法
import { createRouter, createWebHashHistory, useRoute } from "vue-router";
//引入组件
import Home from "../components/Home.vue";
import Login from "../components/Login.vue";
//创建路由对象
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: "/",
component: Home,
},
{
path: "/home",
component: Home,
},
{
path: "/login",
component: Login,
},
],
});
//为了防止用户直接登录home页面,可以使用【路由的前置守卫】进行校验登录
router.beforeEach((to, from, next) => {
//获取上一页的路径进行如下判断
if (to.path == "/login") {
//如果是要去登录页面,直接放行
next();
} else {
//其他资源必须登录之后,才会放行,如果没登陆,则重定向到登录试图
//从sessionStorage中获取用户名,判断先前是否登录,如果登录过放行,否则重定向到登录界面
const username = sessionStorage.getItem("username");
if (username != null) {
//不为null,说明登录过,直接放行
next();
} else {
//否则重定向到登录界面
next("/login");
}
}
});
//对外暴露路由对象
export default router;
结果演示:
路由守卫练习