一、Vue Router的安装
1.创建项目
注:Vue3对应的是Router4版本,Vue2对应的是Router3版本
2.下载router
下载前
下载后
@4是版本,也可以写@4.2.5
--save是使用路由
yarn add vue-router@4 --save二、Vue Router的基本使用
1.目录结构
2.案例代码
About
<template> <div class="about-container"> <h3>About组件</h3> </div> </template> <style scoped> .about-container { min-height: 150px; background-color: #f2f2f2; padding: 15px; } </style>Home
<template> <div class="home-container"> <h3>Home组件</h3> </div> </template> <style scoped> .home-container { min-height: 150px; background-color: #f2f2f2; padding: 15px; } </style>App根组件
<template> <div class="app-container"> <h1>App根组件</h1> <!-- router-link:定义导航链接 --> <!-- to:指定链接的地址,与路由中的path对应 --> <router-link to="/home">首页</router-link> <router-link to="/about">关于</router-link> <hr /> <!-- 路由对应组件显示的位置 --> <router-view></router-view> </div> </template> <style scoped> .app-container { text-align: center; font-size: 16px; } .app-container a { padding: 10px; color: #000; } .app-container a.router-link-active { color: #fff; background-color: #000; } </style>router.js
版本一:一次直接加载所有组件
import {createRouter, createWebHistory} from 'vue-router' import Home from './components/Home.vue' import About from './components/About.vue' const routes = createRouter({ history: createWebHistory(),//history:指定路由模式,createWebHistory()是HTML5的history模式 routes:[ {path:'/home',component:Home}, {path:'/about',component:About}, ] }) export default routes版本二:懒加载动态加载
import {createRouter, createWebHistory} from 'vue-router' // import Home from './components/Home.vue' // import About from './components/About.vue' const routes = createRouter({ history: createWebHistory(),//history:指定路由模式,createWebHistory()是HTML5的history模式 routes:[ {path:'/home',component:()=>import('./components/Home.vue')}, {path:'/about',component:()=>import('./components/About.vue')}, ] }) export default routesmain.js
import { createApp } from 'vue' import './style.css' import App from './App.vue' // 1.引入路由模块 import router from './router.js' const app = createApp(App) // 2.注册路由模块 app.use(router) app.mount('#app')3.效果
三、路由重定向
在第二点案例的基础上,添加重定向代码
router.js
效果
输入http://localhost:5173/会跳转到http://localhost:5173/home
四、嵌套路由
1.目录结构
1.在conponents下新建pages文件夹
2.在pages下新建文件
2.案例代码编写
Tab1
<template> <div>Tab1组件</div> </template> <style scoped> div{ text-align: left; background-color: #9dc4e5; } </style>Tab2
<template> <div>Tab2组件</div> </template> <style scoped> div{ text-align: left; background-color: #ffba00; } </style>About
在第三点的案例基础上
router.js
注:嵌套组件的路径不加‘‘/’’
效果
五、动态路由
1.监听路由
添加到About
效果
2.获取动态路径参数值
法1:$route.params
在components下创建Movie
在根组件App下添加目标地址
在pages下,添加MovieDetails
将Movie和MovieDetails添加到router.js中
效果
法2:props
修改MovieDetails
修改router.js
六、命名路由
模板:
注:name属性是唯一的
修改Home
修改router.js
注:大小写要一致
效果
七、编程式导航
1.两种导航方式
- 声明式导航:<router-link>标签
- 编程式导航:useRouter()函数
2.编程式导航方法
1.push()
push()方法会向历史记录中添加一个新的记录,以编程方式导航到一个新的URL。当用户单击浏览器后退按钮时,会回到之前的URL。push()方法的参数可以是一个字符串路径,或者一个描述地址的对象
router.push('/about/tab1') // 字符串路径 router.push({ path: '/about/tab1' }) // 带有路径的对象 router.push({ name: 'user', params: { userId: '123'} }) // 命名路由 router.push({ path: '/user', query: { id: '1' } }) // 带查询参数,如:/user?id=1 router.push({ path: '/user', hash: '#admin' }) // 带有Hash值,如:/user#admin如果在参数的对象中提供了path,则params会被忽略。为了传递参数,需要提供路由的name或者手动拼接带有参数的path
const id = '123' router.push({ name: '/user', params: { userId } }) // 跳转到/user/123 router.push({ path: `/user/${userId}` }) // 跳转到/user/123 // 以下是params不生效的情况 router.push({ path: '/user', params: { userId } }) // 跳转到/user案例
修改Home:用编程式导航代替声明式导航
2.replace()
replace()方法在导航后不会向历史记录中添加新的记录,而是会替换历史记录中的当前记录。
在声明式导航中,为<router-link>标签添加replace属性也能实现与replace()方法类似的效果。
// 编程式导航 router.replace({ path: '/user' }) <!-- 声明式导航 --> <router-link :to="{ path: '/user' }" replace></router-link>3.go()
go()方法用于实现前进或后退的效果,其参数表示历史记录中前进或后退的步数,类似于window.history.go(),相应的地址栏也会发生改变。
- go(1)表示前进一条记录。
- go(-1)表示后退一条记录。
案例
效果
八、导航守卫
导航守卫用于控制路由的访问权限。
1.规则
const router = createRouter() router.beforeEach((to, from, next) => {})//定义全局前置守卫 router.afterEach((to, from, next) => {})//定义全局后置守卫每个全局导航守卫方法中接收3个形参:to、from和next。
to:表示目标路由对象;
from:表示当前导航正要离开的路由对象;
next:next为函数,如果不接收next()函数,则默认允许用户访问每一个路由;
如果接收了next()函数,则必须调用next()函数,否则不允许用户访问任何一个路由。
2.案例
在conponents下创建Login
在router.js下添加
效果
九、后台管理系统
1.准备工作
1.1创建项目
创建命令:
npm create vite@4.1.0 manage-system选择:
打开vscode,运行项目
// 运行命令 npm run dev // 下载依赖 npm install1.2下载router
下载命令:
yarn add vue-router@4 --save在src文件夹下创建router.js,编写router.js的基本代码
修改mian.js
2.渲染登录组件
2.1把Login写入router
2.2清空App,导入router视图
3.实现登录功能
在components文件夹下创建Login,编写Login代码
<template> <div class="login-container"> <div class="login-box"> <!-- 头像区域 --> <div class="avatar-box"> <img src="../assets/logo.png" class="avatar" /> </div> <!-- 表单区域 --> <div class="form-login"> <!-- 登录名称 --> <div class="form-group"> <label for="username">登录名称:</label> <input type="text" class="form-control" id="username" placeholder="请输入登录名称" autocomplete="off" v-model.trim="username"/> </div> <!-- 登录密码 --> <div class="form-group"> <label for="password">登录密码:</label> <input type="password" class="form-control" id="password" placeholder="请输入登录密码" v-model.trim="password"/> </div> <!-- 登录按钮 --> <div class="form-group"> <button type="button" class="btn" @click="onLogin">登录</button> </div> </div> </div> </div> </template> <script setup> import { ref } from 'vue' import { useRouter } from 'vue-router' const username = ref('') const password = ref('') const router = useRouter() const onLogin = () => { if (username.value === 'admin' && password.value === '123456') { router.push('/home') return localStorage.setItem('token', 'Bearer xxx')//保存token } else { alert('用户名或密码错误') localStorage.removeItem('token')//清除token } } </script>4.渲染后台主页组件
4.1编写首页相关代码
在components下创建Home,编写Home
在components下创建subcomponents文件夹,
在subcomponents下创建MyHeader和MyAside
MyHeader
MyAside
router
将子组件添加到router下
4.2创建各侧边栏子组件
目录
内容
5.实现退出功能
MyHeader
6.全局控制路由访问权限
router
7.渲染用户管理页面的数据
8.跳转到用户详情页
在MyUsers下修改详情功能
在components下创建文件夹users
在users文件夹下创建vue文件MyUserDetail
在router中填写MyUserDetail路径
9.使用props获取用户编号
router添加props
MyUserDetail编写代码
10.解决详情页左侧菜单激活问题
11.解决样式问题
11.1未添加样式
11.2添加样式
11.3样式代码
MyHeader
<style scoped> .layout-header-container { height: 60px; border-bottom: 1px solid #eaeaea; display: flex; justify-content: space-between; align-items: center; padding: 0 0.5rem; background-color: #5f9ea0; .layout-header-left{ display: flex; align-items: center; color: #fff; } } .layout-header-left-img { height: 50px; } .layout-header-right{ .btn{ background-color: #5f9ea0; color: #fff; } .btn:hover{ color: #999; opacity: 0.5; background-color: #fff; } } </style>MyAside
<style scoped> .layout-aside-container { width: 250px; height: 100%; border-right: 1px solid #eaeaea; } .menu { list-style-type: none; padding: 0; .menu-item { line-height: 50px; font-weight: bold; font-size: 14px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; &:hover { background-color: #efefef; cursor: pointer; } a { display: block; color: black; padding-left: 30px; &:hover { text-decoration: none; } } } } /* 设置路由高亮效果 */ .router-link-active { background-color: #efefef; box-sizing: border-box; position: relative; /* 伪元素实现路由高亮效果 */ &::before { content: ' '; display: block; width: 4px; height: 100%; position: absolute; left: 0; top: 0; background-color: #42b983; } } </style>MyUserDetail
<style scoped> button{ background-color: #409eff; color: #fff; } </style>Home
<style> .home-container { height: 100%; display: flex; flex-direction: column; .home-main-box { height: 100%; display: flex; .home-main-body { padding: 15px; flex: 1; } } } </style>Login
<style scoped> .login-container { background-color: #35495e; height: 100%; .login-box { width: 400px; height: 250px; background-color: #fff; border-radius: 3px; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); box-shadow: 0 0 6px rgba(255, 255, 255, 0.5); .form-login { position: absolute; bottom: 0; left: 0; width: 100%; box-sizing: border-box; padding: 1.5rem!important; .form-group{ padding-top: 20px; .btn{ background-color:deepskyblue; color: #fff; } } } } } .form-control{ flex: 1; padding: 0.5rem; } .avatar-box { position: absolute; width: 100%; top: -65px; left: 0; .avatar { width: 120px; height: 120px; border-radius: 50% !important; box-shadow: 0 0 6px #efefef; background-color: #fff; } } </style>style.css
:root { font-family: Inter, Avenir, Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; font-weight: 400; color-scheme: light dark; color: rgba(255, 255, 255, 0.87); background-color: #242424; font-synthesis: none; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; -webkit-text-size-adjust: 100%; } a { font-weight: 500; color: #646cff; text-decoration: inherit; } a:hover { color: #535bf2; } a { font-weight: 500; color: #646cff; text-decoration: inherit; } a:hover { color: #535bf2; } /* body { margin: 0; display: flex; place-items: center; min-width: 320px; min-height: 100vh; } */ body { margin: 0; display: flex; place-items: center; height: 100%; } html{ height: 100%; } h1 { font-size: 3.2em; line-height: 1.1; } button { border-radius: 8px; border: 1px solid transparent; padding: 0.6em 1.2em; font-size: 1em; font-weight: 500; font-family: inherit; background-color: #1a1a1a; cursor: pointer; transition: border-color 0.25s; } button:hover { border-color: #646cff; } button:focus, button:focus-visible { outline: 4px auto -webkit-focus-ring-color; } .card { padding: 2em; } /* #app { width: 1280px; margin: 0 auto; padding: 2rem; text-align: center; } */ #app { width: 100%; margin: 0 auto; text-align: center; height: 100%; } @media (prefers-color-scheme: light) { :root { color: #213547; background-color: #ffffff; } a:hover { color: #747bff; } button { background-color: #f9f9f9; } }12.完整代码
目录
代码
省略。。。