前端【VUE】07-vue【路由】【声明式导航【导航高亮-精确匹配和模糊匹配】【自定义高亮类名】【导航传参】】【编程式导航【导航传参【查询参数传参、动态路由传参】】】【路由守卫】
一、路由
单页应用程序: SPA - Single Page Application
VueRouter 的 介绍
作用:修改地址栏路径时,切换显示匹配的组件
说明:Vue 官方的一个路由插件,是一个第三方包
官网:https://v3.router.vuejs.org/zh/
vue2 对应 router3
vue3 对应 router4
1、如果配置了二级路由,则访问二级路由时就是使用: 一级路由/二级路由
1 { 2 path: '/park', 3 component: Layout, 4 permission: 'park', 5 meta: { title: '园区管理', icon: 'el-icon-office-building' }, 6 children: [ 7 { 8 path: 'building', // 访问: 二级路由 /park/building 9 permission: 'park:building', 10 meta: { title: '楼宇管理' }, 11 component: () => import('@/views/Park/Building/index') 12 }, 13 { 14 path: 'enterprise', // /park/enterprise 15 permission: 'park:enterprise', 16 meta: { title: '企业管理' }, 17 component: () => import('@/views/Park/Enterprise/index') 18 } 19 ] 20 }
2、如果配置了二级路由,但是二级路由的path为'', 此时访问一级路由,就相当于访问二级路由
1 { 2 path: '/workbench', 3 component: Layout, 4 children: [ 5 { 6 path: '', 7 component: () => import('@/views/Workbench/index'), 8 meta: { title: '工作台', icon: 'el-icon-data-board' } 9 } 10 ] 11 }
通过注入路由器,我们可以在任何组件内通过 this. r o u t e r 访 问 路 由 器 , 也 可 以 通 过 t h i s . router 访问路由器,也可以通过 this. router访问路由器,也可以通过this.route 访问当前路由.
通过打印出: this.$router 和 this. $route :
this.$router(路由实例) : 是VueRouter的实例.包含了很多属性和对象(比如 history 对象),任何页面都可以调用其 push(), replace(), go() 等方法。
this.$route: 表示当前路由对象,每一个路由都会有一个 route 对象,是一个局部的对象,可以获取对应的 name, path, meta, params, query 等属性。
1 $route.path 2 类型: string 3 字符串,对应当前路由的路径,总是解析为绝对路径,如 /foo/bar。 4 5 $route.params 6 类型: Object 7 一个 key/value 对象,包含了动态片段和全匹配片段,如果没有路由参数,就是一个空对象。 8 9 $route.query 10 类型: Object 11 一个key/value 对象,表示 URL 查询参数。例如,对于路径/foo?user=1,则有 $route.query.user == 1,如果没有查询参数,则是个空对象。 12 13 $route.matched 14 类型:Array 15 一个数组,包含当前路由的所有嵌套路径片段的路由记录 。路由记录就是 routes 配置数组中的对象副本 (还有在 children 数组)。 16 $route.fullPath 17 路由是:/path/:type真正路径是:/path/list 18 path匹配路径: /path/list 19 fullPath匹配路由: /path/:type 20 21 $route.meta (路由原信息meta) 22 const router = new VueRouter({ 23 routes: [ 24 { 25 path: '/foo', 26 component: Foo, 27 children: [ 28 { 29 path: 'bar', 30 component: Bar, 31 // a meta field 32 meta: { requiresAuth: true ,keepAlive:true}//1.权限 2.内存缓存,单页面切换 33 } 34 ] 35 } 36 ] 37 }) 38 39 $route.matched 40 一个数组,包含当前路由的所有嵌套路径片段的路由记录 41 一个路由匹配到的所有路由记录会暴露为 $route 对象 (还有在导航守卫中的路由对象) 的 $route.matched 数组 42 43 路由元信息 .meta $route.matched 搭配路由守卫 进行验证 44 router.beforeEach((to, from, next) => { 45 if (to.matched.some(record => record.meta.requiresAuth)) { 46 // this route requires auth, check if logged in 47 // if not, redirect to login page. 48 if (!auth.loggedIn()) { 49 next({ 50 path: '/login', 51 query: { redirect: to.fullPath } 52 }) 53 } else { 54 next() 55 } 56 } else { 57 next() // 确保一定要调用 next() 58 } 59 })
获取当前页面的路由:
1 this.$route.fullPath
1、正常导入方式
1 import Vue from 'vue' 2 import VueRouter from 'vue-router' 3 import { getToken } from '@/utils/storage' 4 // 导入路由 5 import Login from '@/views/Layout' 6 import Register from '@/views/Register' 7 import Article from @/views/Article' 8 import Collect from '@/views/Collect' 9 10 Vue.use(VueRouter) 11 12 const router = new VueRouter({ 13 // 注册路由 14 routes: [ 15 { path: '/login', component: Login }, 16 { path: '/register', component: Register }, 17 { 18 path: '/', 19 component: Layout, 20 redirect: '/article', 21 children: [ 22 { path: '/article', component: Article }, 23 { path: '/collect', component: Collect }, 24 ] 25 } 26 ] 27 }) 28 29 // 白名单(就是一个数组,数组收录所有无需登录即可访问的页面) 30 const whiteList = ['/login', '/register'] 31 32 // 路由前置守卫 33 // 1. to 往哪去 34 // 2. from 从哪来 35 // 3. next 是否放行 next() 放行 next(路径) 拦截到某个页面 36 router.beforeEach((to, from, next) => { 37 const token = getToken() 38 if (token) { 39 // 如果有token,直接放行 40 next() 41 } else { 42 // 没有token的人,看看要去哪 43 // 判断访问的路径 to.path, 是否在白名单中 44 if (whiteList.includes(to.path)) { 45 next() 46 } else { 47 next('/login') 48 } 49 } 50 }) 51 52 export default router
2、通过箭头函数导入组件
1 import Vue from 'vue' 2 import VueRouter from 'vue-router' 3 import { getToken } from '@/utils/storage' 4 import Login from '@/views/Layout.vue' 5 6 // 一级路由页面的导入 7 const Login = () => import('@/views/Login') 8 const Register = () => import('@/views/Register') 9 const Layout = () => import('@/views/Layout') 10 const Detail = () => import('@/views/Detail') 11 12 Vue.use(VueRouter) 13 14 const router = new VueRouter({ 15 routes: [ 16 { path: '/login', component: Login }, 17 { path: '/register', component: Register }, 18 // 动态路由传参的方式 19 { path: '/article/:id', component: Detail }, 20 { 21 path: '/', 22 component: Layout, 23 redirect: '/article', 24 children: [ 25 { path: '/article', component: () => import('@/views/Article') }, 26 { path: '/like', component: () => import('@/views/Like') }, 27 { path: '/collect', component: () => import('@/views/Collect') }, 28 { path: '/user', component: () => import('@/views/User') } 29 ] 30 } 31 ] 32 }) 33 34 // 白名单(就是一个数组,数组收录所有无需登录即可访问的页面) 35 const whiteList = ['/login', '/register'] 36 37 // 路由前置守卫 38 // 1. to 往哪去 39 // 2. from 从哪来 40 // 3. next 是否放行 next() 放行 next(路径) 拦截到某个页面 41 router.beforeEach((to, from, next) => { 42 const token = getToken() 43 if (token) { 44 // 如果有token,直接放行 45 next() 46 } else { 47 // 没有token的人,看看要去哪 48 // 判断访问的路径 to.path, 是否在白名单中 49 if (whiteList.includes(to.path)) { 50 next() 51 } else { 52 next('/login') 53 } 54 } 55 }) 56 57 export default router
VueRouter 的 使用
1、下载
1 npm i vue-router@3.6.5
2、项目中新增views目录,存放各个视图页面
views/Find.vue
1 <template> 2 <div> 3 <p>我的音乐</p> 4 <p>我的音乐</p> 5 <p>我的音乐</p> 6 <p>我的音乐</p> 7 </div> 8 </template> 9 10 <script> 11 export default { 12 name: 'MyMusic' 13 } 14 </script> 15 <style> 16 </style>
views/Friend.vue
1 <template> 2 <div> 3 <p>我的朋友</p> 4 <p>我的朋友</p> 5 <p>我的朋友</p> 6 <p>我的朋友</p> 7 </div> 8 </template> 9 10 <script> 11 export default { 12 name: 'MyFriend' 13 } 14 </script> 15 <style> 16 </style>
views/My.vue
1 <template> 2 <div> 3 <p>我的音乐</p> 4 <p>我的音乐</p> 5 <p>我的音乐</p> 6 <p>我的音乐</p> 7 </div> 8 </template> 9 10 <script> 11 export default { 12 name: 'MyMusic' 13 } 14 </script> 15 <style> 16 </style>
3、根组件App.vue中添加路由出口,也就是用来路由到不同视图的位置
1 <template> 2 <div> 3 <div class="footer_wrap"> 4 <a href="#/find">发现音乐</a> 5 <a href="#/my">我的音乐</a> 6 <a href="#/friend">朋友</a> 7 </div> 8 <div class="top"> 9 <!-- 路由出口 → 匹配的组件所展示的位置 --> 10 <router-view></router-view> 11 </div> 12 </div> 13 </template> 14 15 <script> 16 export default {}; 17 </script> 18 19 <style> 20 body { 21 margin: 0; 22 padding: 0; 23 } 24 .footer_wrap { 25 position: relative; 26 left: 0; 27 top: 0; 28 display: flex; 29 width: 100%; 30 text-align: center; 31 background-color: #333; 32 color: #ccc; 33 } 34 .footer_wrap a { 35 flex: 1; 36 text-decoration: none; 37 padding: 20px 0; 38 line-height: 20px; 39 background-color: #333; 40 color: #ccc; 41 border: 1px solid black; 42 } 43 .footer_wrap a:hover { 44 background-color: #555; 45 } 46 </style>
4、main.js中定义路由,并且注册到vue实例中,后续写项目会将路由单独写到router目录下index.js中,通过export导出定义的路由组件,然后在main.js中导入定义的路由进行注册
1 import Vue from 'vue' 2 import App from './App.vue' 3 4 // 路由的使用步骤 5 + 2 5 // 5个基础步骤 6 // 1. 下载 v3.6.5 7 // 2. 引入 8 // 3. 安装注册 Vue.use(Vue插件) 9 // 4. 创建路由对象 10 // 5. 注入到new Vue中,建立关联 11 12 // 2个核心步骤 13 // 1. 建组件(views目录),配规则 14 // 2. 准备导航链接,配置路由出口(匹配的组件展示的位置) 15 import Find from './views/Find' 16 import My from './views/My' 17 import Friend from './views/Friend' 18 import VueRouter from 'vue-router' 19 Vue.use(VueRouter) // VueRouter插件初始化 20 21 const router = new VueRouter({ 22 // routes 路由规则们 23 // route 一条路由规则 { path: 路径, component: 组件 } 24 routes: [ 25 { path: '/find', component: Find }, 26 { path: '/my', component: My }, 27 { path: '/friend', component: Friend }, 28 ] 29 }) 30 31 Vue.config.productionTip = false 32 33 new Vue({ 34 render: h => h(App), 35 router 36 }).$mount('#app')
组件存放目录问题
路由的封装抽离
1、目录结构
2、路由目录
router/index.js
1 import Find from '@/views/Find' 2 import My from '@/views/My' 3 import Friend from '@/views/Friend' 4 5 import Vue from 'vue' 6 import VueRouter from 'vue-router' 7 Vue.use(VueRouter) // VueRouter插件初始化 8 9 // 创建了一个路由对象 10 const router = new VueRouter({ 11 // routes 路由规则们 12 // route 一条路由规则 { path: 路径, component: 组件 } 13 routes: [ 14 { path: '/find', component: Find }, 15 { path: '/my', component: My }, 16 { path: '/friend', component: Friend }, 17 ] 18 }) 19 20 export default router
3、视图目录
views/Find.vue
1 <template> 2 <div> 3 <p>发现音乐</p> 4 <p>发现音乐</p> 5 <p>发现音乐</p> 6 <p>发现音乐</p> 7 </div> 8 </template> 9 10 <script> 11 export default { 12 name: 'FindMusic' 13 } 14 </script> 15 <style> 16 </style>
views/Friend.vue
1 <template> 2 <div> 3 <p>我的朋友</p> 4 <p>我的朋友</p> 5 <p>我的朋友</p> 6 <p>我的朋友</p> 7 </div> 8 </template> 9 10 <script> 11 export default { 12 name: 'MyFriend' 13 } 14 </script> 15 <style> 16 </style>
views/My.vue
1 <template> 2 <div> 3 <p>我的音乐</p> 4 <p>我的音乐</p> 5 <p>我的音乐</p> 6 <p>我的音乐</p> 7 </div> 8 </template> 9 10 <script> 11 export default { 12 name: 'MyMusic' 13 } 14 </script> 15 <style> 16 </style>
4、根组件App.vue
1 <template> 2 <div> 3 <div class="footer_wrap"> 5 <a href="#/find">发现音乐</a> 6 <a href="#/my">我的音乐</a> 7 <a href="#/friend">朋友</a> 8 </div> 9 <div class="top"> 10 <!-- 2、路由出口 → 匹配的组件所展示的位置 --> 11 <router-view></router-view> 12 </div> 13 </div> 14 </template> 15 16 <script> 17 export default {}; 18 </script> 19 20 <style> 21 body { 22 margin: 0; 23 padding: 0; 24 } 25 .footer_wrap { 26 position: relative; 27 left: 0; 28 top: 0; 29 display: flex; 30 width: 100%; 31 text-align: center; 32 background-color: #333; 33 color: #ccc; 34 } 35 .footer_wrap a { 36 flex: 1; 37 text-decoration: none; 38 padding: 20px 0; 39 line-height: 20px; 40 background-color: #333; 41 color: #ccc; 42 border: 1px solid black; 43 } 44 .footer_wrap a:hover { 45 background-color: #555; 46 } 47 </style>
5、main.js
1 import Vue from 'vue' 2 import App from './App.vue' 3 import router from './router/index' 4 5 Vue.config.productionTip = false 6 7 new Vue({ 8 render: h => h(App), 9 router 10 }).$mount('#app')
声明式导航 - 导航链接
1、router目录下index.js
1 import Find from '@/views/Find' 2 import My from '@/views/My' 3 import Friend from '@/views/Friend' 4 5 import Vue from 'vue' 6 import VueRouter from 'vue-router' 7 Vue.use(VueRouter) // VueRouter插件初始化 8 9 // 创建了一个路由对象 10 const router = new VueRouter({ 11 // routes 路由规则们 12 // route 一条路由规则 { path: 路径, component: 组件 } 13 routes: [ 14 { path: '/find', component: Find }, 15 { path: '/my', component: My }, 16 { path: '/friend', component: Friend }, 17 ] 18 }) 19 20 export default router
2、视图目录下
views/Find.vue
1 <template> 2 <div> 3 <p>发现音乐</p> 4 <p>发现音乐</p> 5 <p>发现音乐</p> 6 <p>发现音乐</p> 7 </div> 8 </template> 9 10 <script> 11 export default { 12 name: 'FindMusic' 13 } 14 </script> 15 <style> 16 </style>
views/Friend.vue
1 <template> 2 <div> 3 <p>我的朋友</p> 4 <p>我的朋友</p> 5 <p>我的朋友</p> 6 <p>我的朋友</p> 7 </div> 8 </template> 9 10 <script> 11 export default { 12 name: 'MyFriend' 13 } 14 </script> 15 <style> 16 </style>
views/My.vue
1 <template> 2 <div> 3 <p>我的音乐</p> 4 <p>我的音乐</p> 5 <p>我的音乐</p> 6 <p>我的音乐</p> 7 </div> 8 </template> 9 10 <script> 11 export default { 12 name: 'MyMusic' 13 } 14 </script> 15 <style> 16 </style>
3、根组件App.vue,使用route-link替换调a标签,使用router-link标签,相较于上面使用a标签,多了两个类名。router-link-active 和 router-link-exact-active
1 <template> 2 <div> 3 <div class="footer_wrap"> 4 <router-link to="/find">发现音乐</router-link> 5 <router-link to="/my">我的音乐</router-link> 6 <router-link to="/friend">朋友</router-link> 7 </div> 8 <div class="top"> 9 <!-- 路由出口 → 匹配的组件所展示的位置 --> 10 <router-view></router-view> 11 </div> 12 </div> 13 </template> 14 15 <script> 16 export default {}; 17 </script> 18 19 <style> 20 body { 21 margin: 0; 22 padding: 0; 23 } 24 .footer_wrap { 25 position: relative; 26 left: 0; 27 top: 0; 28 display: flex; 29 width: 100%; 30 text-align: center; 31 background-color: #333; 32 color: #ccc; 33 } 34 .footer_wrap a { 35 flex: 1; 36 text-decoration: none; 37 padding: 20px 0; 38 line-height: 20px; 39 background-color: #333; 40 color: #ccc; 41 border: 1px solid black; 42 } 43 .footer_wrap a.router-link-active { // 模糊匹配,地址栏/find 或者/find/one 都会匹配 44 background-color: purple; 45 } 46 .footer_wrap a:hover { 47 background-color: #555; 48 } 49 </style>
4、main.js
1 import Vue from 'vue' 2 import App from './App.vue' 3 import router from './router/index' 4 5 Vue.config.productionTip = false 6 7 new Vue({ 8 render: h => h(App), 9 router 10 }).$mount('#app')
声明式导航-导航高亮 两个类名
1 // router-link-active 模糊匹配(更多) 2 // to="/find" => 地址栏: /find 或 /find/one 或 /find/two 3 .footer_wrap a.router-link-active { 4 background-color: purple; 5 } 6 7 // router-link-exact-active 精确匹配 8 // to="/find" => 地址栏只能是 /find 才会高亮 9 .footer_wrap a.router-link-active { 10 background-color: purple; 11 }
声明式导航-自定义高亮类名
1、router目录下index.js
1 import Find from '@/views/Find' 2 import My from '@/views/My' 3 import Friend from '@/views/Friend' 4 5 import Vue from 'vue' 6 import VueRouter from 'vue-router' 7 Vue.use(VueRouter) // VueRouter插件初始化 8 9 // 创建了一个路由对象 10 const router = new VueRouter({ 11 // routes 路由规则们 12 // route 一条路由规则 { path: 路径, component: 组件 } 13 routes: [ 14 { path: '/find', component: Find }, 15 { path: '/my', component: My }, 16 { path: '/friend', component: Friend }, 17 ], 18 // link自定义高亮类名 19 linkActiveClass: 'active', // 配置模糊匹配的类名 20 linkExactActiveClass: 'exact-active' // 配置精确匹配的类名 21 }) 22 23 export default router
2、views视图目录下
Find.vue
1 <template> 2 <div> 3 <p>发现音乐</p> 4 <p>发现音乐</p> 5 <p>发现音乐</p> 6 <p>发现音乐</p> 7 </div> 8 </template> 9 10 <script> 11 export default { 12 name: 'FindMusic' 13 } 14 </script> 15 <style> 16 </style>
Friend.vue
1 <template> 2 <div> 3 <p>我的朋友</p> 4 <p>我的朋友</p> 5 <p>我的朋友</p> 6 <p>我的朋友</p> 7 </div> 8 </template> 9 10 <script> 11 export default { 12 name: 'MyFriend' 13 } 14 </script> 15 <style> 16 </style>
My.vue
1 <template> 2 <div> 3 <p>我的音乐</p> 4 <p>我的音乐</p> 5 <p>我的音乐</p> 6 <p>我的音乐</p> 7 </div> 8 </template> 9 10 <script> 11 export default { 12 name: 'MyMusic' 13 } 14 </script> 15 <style> 16 </style>
3、根组件App.vue
1 <template> 2 <div> 3 <div class="footer_wrap"> 4 <router-link to="/find">发现音乐</router-link> 5 <router-link to="/my">我的音乐</router-link> 6 <router-link to="/friend">朋友</router-link> 7 </div> 8 <div class="top"> 9 <!-- 路由出口 → 匹配的组件所展示的位置 --> 10 <router-view></router-view> 11 </div> 12 </div> 13 </template> 14 15 <script> 16 export default {}; 17 </script> 18 19 <style> 20 body { 21 margin: 0; 22 padding: 0; 23 } 24 .footer_wrap { 25 position: relative; 26 left: 0; 27 top: 0; 28 display: flex; 29 width: 100%; 30 text-align: center; 31 background-color: #333; 32 color: #ccc; 33 } 34 .footer_wrap a { 35 flex: 1; 36 text-decoration: none; 37 padding: 20px 0; 38 line-height: 20px; 39 background-color: #333; 40 color: #ccc; 41 border: 1px solid black; 42 } 43 .footer_wrap a.active { // 使用自定义的高亮类名 44 background-color: purple; 45 } 46 .footer_wrap a:hover { 47 background-color: #555; 48 } 49 </style>
4、main.js
1 import Vue from 'vue' 2 import App from './App.vue' 3 import router from './router/index' 4 5 Vue.config.productionTip = false 6 7 new Vue({ 8 render: h => h(App), 9 router 10 }).$mount('#app')
声明式导航-路由嵌套
1、reouter目录下index.js
1 import Find from "@/views/Find"; 2 import My from "@/views/My"; 3 import Friend from "@/views/Friend"; 4 5 import Recommend from "@/views/Recommend"; 6 import ArtList from "@/views/ArtList"; 7 import TopList from "@/views/TopList"; 8 9 import Vue from "vue"; 10 import VueRouter from "vue-router"; 11 Vue.use(VueRouter); // VueRouter插件初始化 12 13 // 创建了一个路由对象 14 const router = new VueRouter({ 15 routes: [ 16 { 17 path: "/find", 18 component: Find, 19 // 嵌套的子路由, 省略前缀/, 会自动拼接父路由地址/find/recommend 20 children: [ 21 { path: "recommend", component: Recommend }, 22 { path: "artlist", component: ArtList }, 23 { path: "toplist", component: TopList }, 24 ], 25 }, 26 { path: "/my", component: My }, 27 { path: "/friend", component: Friend }, 28 ], 29 }); 30 31 export default router;
2、视图目录下
views/Find.vue
1 <template> 2 <div class="box"> 3 <!-- 发现音乐 --> 4 <div class="link"> 5 <router-link to="/find/recommend">推荐</router-link> 6 <router-link to="/find/toplist">排行榜</router-link> 7 <router-link to="/find/artlist">歌手</router-link> 8 </div> 9 <div class="content"> 10 <router-view></router-view> 11 </div> 12 </div> 13 </template> 14 15 <script> 16 export default { 17 name: 'FindMusic' 18 } 19 </script> 20 21 <style lang="less" scoped> 22 .box { 23 padding: 15px; 24 } 25 26 .link { 27 a { 28 padding-right: 10px; 29 text-decoration: none; 30 color: #424242; 31 } 32 } 33 34 .content { 35 padding: 10px; 36 } 37 </style>
views/Friend.vue
1 <template> 2 <div> 3 <p>我的朋友</p> 4 <p>我的朋友</p> 5 <p>我的朋友</p> 6 <p>我的朋友</p> 7 </div> 8 </template> 9 10 <script> 11 export default { 12 name: 'MyFriend' 13 } 14 </script> 15 <style> 16 </style>
views/My.vue
1 <template> 2 <div> 3 <p>我的音乐</p> 4 <p>我的音乐</p> 5 <p>我的音乐</p> 6 <p>我的音乐</p> 7 </div> 8 </template> 9 10 <script> 11 export default { 12 name: 'MyMusic' 13 } 14 </script> 15 <style> 16 </style>
Find下面的子路由
views/ArtList.vue
1 <template> 2 <div> 3 <h3>歌手</h3> 4 </div> 5 </template> 6 7 <script> 8 export default { 9 name: 'ArtList' 10 } 11 </script> 12 13 <style lang="less" scoped> 14 </style>
views/Recommend.vue
1 <template> 2 <div> 3 <h2>推荐</h2> 4 </div> 5 </template> 6 7 <script> 8 export default { 9 name: 'recommendPage' 10 } 11 </script> 12 13 <style lang="less" scoped></style>
views/TopList.vue
1 <template> 2 <div> 3 <h2>排行榜</h2> 4 </div> 5 </template> 6 7 <script> 8 export default { 9 name: 'TopList' 10 } 11 </script> 12 13 <style lang="less" scoped> 14 </style>
3、根组件App.vue
1 <template> 2 <div> 3 <div class="footer_wrap"> 4 <router-link to="/find">发现音乐</router-link> 5 <router-link to="/my">我的音乐</router-link> 6 <router-link to="/friend">朋友</router-link> 7 </div> 8 <div class="top"> 9 <!-- 路由出口 → 匹配的组件所展示的位置 --> 10 <router-view></router-view> 11 </div> 12 </div> 13 </template> 14 15 <script> 16 export default {}; 17 </script> 18 19 <style> 20 body { 21 margin: 0; 22 padding: 0; 23 } 24 .footer_wrap { 25 position: relative; 26 left: 0; 27 top: 0; 28 display: flex; 29 width: 100%; 30 text-align: center; 31 background-color: #333; 32 color: #ccc; 33 } 34 .footer_wrap a { 35 flex: 1; 36 text-decoration: none; 37 padding: 20px 0; 38 line-height: 20px; 39 background-color: #333; 40 color: #ccc; 41 border: 1px solid black; 42 } 43 .footer_wrap a.router-link-active { 44 background-color: purple; 45 } 46 .footer_wrap a:hover { 47 background-color: #555; 48 } 49 </style>
4、main.js
1 import Vue from 'vue' 2 import App from './App.vue' 3 import router from './router/index' 4 5 Vue.config.productionTip = false 6 7 new Vue({ 8 render: h => h(App), 9 router 10 }).$mount('#app')
声明式导航-路由传参
目标:在跳转路由时, 进行传值
1、router/index.js
1 import Home from '@/views/Home' 2 import Search from '@/views/Search' 3 import Vue from 'vue' 4 import VueRouter from 'vue-router' 5 Vue.use(VueRouter) // VueRouter插件初始化 6 7 // 创建了一个路由对象 8 const router = new VueRouter({ 9 routes: [ 10 { path: '/home', component: Home }, 11 { path: '/search', component: Search } 12 ] 13 }) 14 15 export default router
2、视图页面
views/Home.vue
1 <template> 2 <div class="home"> 3 <div class="logo-box"></div> 4 <div class="search-box"> 5 <input type="text"> 6 <button>搜索一下</button> 7 </div> 8 <div class="hot-link"> 9 热门搜索: 10 <!-- 通过路由跳转的时候, 将查询参数传递到子路由 --> 11 <router-link to="/search?key=黑马程序员">黑马程序员</router-link> 12 <router-link to="/search?key=前端培训">前端培训</router-link> 13 <router-link to="/search?key=如何成为前端大牛">如何成为前端大牛</router-link> 14 </div> 15 </div> 16 </template> 17 18 <script> 19 export default { 20 name: 'FindMusic' 21 } 22 </script> 23 24 <style> 25 .logo-box { 26 height: 150px; 27 background: url('@/assets/logo.jpeg') no-repeat center; 28 } 29 .search-box { 30 display: flex; 31 justify-content: center; 32 } 33 .search-box input { 34 width: 400px; 35 height: 30px; 36 line-height: 30px; 37 border: 2px solid #c4c7ce; 38 border-radius: 4px 0 0 4px; 39 outline: none; 40 } 41 .search-box input:focus { 42 border: 2px solid #ad2a26; 43 } 44 .search-box button { 45 width: 100px; 46 height: 36px; 47 border: none; 48 background-color: #ad2a26; 49 color: #fff; 50 position: relative; 51 left: -2px; 52 border-radius: 0 4px 4px 0; 53 } 54 .hot-link { 55 width: 508px; 56 height: 60px; 57 line-height: 60px; 58 margin: 0 auto; 59 } 60 .hot-link a { 61 margin: 0 5px; 62 } 63 </style>
views/Search.vue
1 <template> 2 <div class="search"> 3 <p>搜索关键字: {{ $route.query.key }} </p> 4 <p>搜索结果: </p> 5 <ul> 6 <li>.............</li> 7 <li>.............</li> 8 <li>.............</li> 9 <li>.............</li> 10 </ul> 11 </div> 12 </template> 13 14 <script> 15 export default { 16 name: 'MyFriend', 17 created () { 18 // 在created中,获取路由参数 19 // this.$route.query.参数名 获取 20 console.log(this.$route.query.key); 21 } 22 } 23 </script> 24 25 <style> 26 .search { 27 width: 400px; 28 height: 240px; 29 padding: 0 20px; 30 margin: 0 auto; 31 border: 2px solid #c4c7ce; 32 border-radius: 5px; 33 } 34 </style>
3、根组件App.vue
1 <template> 2 <div id="app"> 3 <div class="link"> 4 <router-link to="/home">首页</router-link> 5 <router-link to="/search">搜索页</router-link> 6 </div> 7 8 <router-view></router-view> 9 </div> 10 </template> 11 12 <script> 13 export default {}; 14 </script> 15 16 <style scoped> 17 .link { 18 height: 50px; 19 line-height: 50px; 20 background-color: #495150; 21 display: flex; 22 margin: -8px -8px 0 -8px; 23 margin-bottom: 50px; 24 } 25 .link a { 26 display: block; 27 text-decoration: none; 28 background-color: #ad2a26; 29 width: 100px; 30 text-align: center; 31 margin-right: 5px; 32 color: #fff; 33 border-radius: 5px; 34 } 35 </style>
4、main.js
1 import Vue from 'vue' 2 import App from './App.vue' 3 import router from './router/index' 4 5 Vue.config.productionTip = false 6 7 new Vue({ 8 render: h => h(App), 9 router 10 }).$mount('#app')
1、router/index.js
1 import Home from '@/views/Home' 2 import Search from '@/views/Search' 3 import Vue from 'vue' 4 import VueRouter from 'vue-router' 5 Vue.use(VueRouter) // VueRouter插件初始化 6 7 // 创建了一个路由对象 8 const router = new VueRouter({ 9 routes: [ 10 { path: '/home', component: Home }, 11 // path: '/search/:参数1/:参数2' 12 { path: '/search/:words', component: Search } 13 ] 14 }) 15 16 export default router
2、视图页面
views/Home.vue
1 <template> 2 <div class="home"> 3 <div class="logo-box"></div> 4 <div class="search-box"> 5 <input type="text"> 6 <button>搜索一下</button> 7 </div> 8 <div class="hot-link"> 9 热门搜索: 10 <!-- 通过动态路由传参 --> 11 <router-link to="/search/黑马程序员">黑马程序员</router-link> 12 <router-link to="/search/前端培训">前端培训</router-link> 13 <router-link to="/search/如何成为前端大牛">如何成为前端大牛</router-link> 14 </div> 15 </div> 16 </template> 17 18 <script> 19 export default { 20 name: 'FindMusic' 21 } 22 </script> 23 24 <style> 25 .logo-box { 26 height: 150px; 27 background: url('@/assets/logo.jpeg') no-repeat center; 28 } 29 .search-box { 30 display: flex; 31 justify-content: center; 32 } 33 .search-box input { 34 width: 400px; 35 height: 30px; 36 line-height: 30px; 37 border: 2px solid #c4c7ce; 38 border-radius: 4px 0 0 4px; 39 outline: none; 40 } 41 .search-box input:focus { 42 border: 2px solid #ad2a26; 43 } 44 .search-box button { 45 width: 100px; 46 height: 36px; 47 border: none; 48 background-color: #ad2a26; 49 color: #fff; 50 position: relative; 51 left: -2px; 52 border-radius: 0 4px 4px 0; 53 } 54 .hot-link { 55 width: 508px; 56 height: 60px; 57 line-height: 60px; 58 margin: 0 auto; 59 } 60 .hot-link a { 61 margin: 0 5px; 62 } 63 </style>
views/Search.vue
1 <template> 2 <div class="search"> 3 <p>搜索关键字: {{ $route.params.words }} </p> 4 <p>搜索结果: </p> 5 <ul> 6 <li>.............</li> 7 <li>.............</li> 8 <li>.............</li> 9 <li>.............</li> 10 </ul> 11 </div> 12 </template> 13 14 <script> 15 export default { 16 name: 'MyFriend', 17 created () { 18 // 在created中,获取路由参数 19 // this.$route.query.参数名 获取查询参数 20 // this.$route.params.参数名 获取动态路由参数 21 console.log(this.$route.params.words); 22 } 23 } 24 </script> 25 26 <style> 27 .search { 28 width: 400px; 29 height: 240px; 30 padding: 0 20px; 31 margin: 0 auto; 32 border: 2px solid #c4c7ce; 33 border-radius: 5px; 34 } 35 </style>
3、根组件App.vue
1 <template> 2 <div id="app"> 3 <div class="link"> 4 <router-link to="/home">首页</router-link> 5 <router-link to="/search">搜索页</router-link> 6 </div> 7 <router-view></router-view> 8 </div> 9 </template> 10 11 <script> 12 export default {}; 13 </script> 14 15 <style scoped> 16 .link { 17 height: 50px; 18 line-height: 50px; 19 background-color: #495150; 20 display: flex; 21 margin: -8px -8px 0 -8px; 22 margin-bottom: 50px; 23 } 24 .link a { 25 display: block; 26 text-decoration: none; 27 background-color: #ad2a26; 28 width: 100px; 29 text-align: center; 30 margin-right: 5px; 31 color: #fff; 32 border-radius: 5px; 33 } 34 </style>
4、main.js
1 import Vue from 'vue' 2 import App from './App.vue' 3 import router from './router/index' 4 5 Vue.config.productionTip = false 6 7 new Vue({ 8 render: h => h(App), 9 router 10 }).$mount('#app')
动态路由参数可选符
1 import Home from '@/views/Home' 2 import Search from '@/views/Search' 3 import Vue from 'vue' 4 import VueRouter from 'vue-router' 5 Vue.use(VueRouter) // VueRouter插件初始化 6 7 // 创建了一个路由对象 8 const router = new VueRouter({ 9 routes: [ 10 { path: '/home', component: Home }, 11 // path: '/search/:words?' -> ? 表示参数words可以没有, 此时路由匹配: /search 和 带参数的 /search/:words, :后面的words为自定义变量,用于子路由获取传参时使用, this.$route.params.words ,这个words与:后面的单词保持一致 12 { path: '/search/:words?', component: Search } 13 ] 14 }) 15 16 export default router
路由重定向
router/index.js 路由配置的js文件
1 import Home from '@/views/Home' 2 import Search from '@/views/Search' 3 import Vue from 'vue' 4 import VueRouter from 'vue-router' 5 Vue.use(VueRouter) // VueRouter插件初始化 6 7 // 创建了一个路由对象 8 const router = new VueRouter({ 9 routes: [ 10 // 路由重定向,当我们访问项目根目录的时候, 默认重定向到/home视图 11 { path: '/', redirect: '/home' }, 12 { path: '/home', component: Home }, 13 { path: '/search/:words?', component: Search } 14 ] 15 }) 16 17 export default router
路由404
1 import Home from '@/views/Home' 2 import Search from '@/views/Search' 3 import NotFound from '@/views/NotFound' 4 import Vue from 'vue' 5 import VueRouter from 'vue-router' 6 Vue.use(VueRouter) // VueRouter插件初始化 7 8 // 创建了一个路由对象 9 const router = new VueRouter({ 10 routes: [ 11 // 路由重定向, 当我们访问项目根目录的时候, 默认重定向到/home视图 12 { path: '/', redirect: '/home' }, 13 { path: '/home', component: Home }, 14 { path: '/search/:words?', component: Search }, 15 // 通配符, 当上面的所有路由规则都没有匹配到时, 走这条兜底规则, 展示默认的NotFound页面 16 { path: '*', component: NotFound } 17 ] 18 }) 19 20 export default router
路由模式设置
1 import Home from '@/views/Home' 2 import Search from '@/views/Search' 3 import NotFound from '@/views/NotFound' 4 import Vue from 'vue' 5 import VueRouter from 'vue-router' 6 Vue.use(VueRouter) // VueRouter插件初始化 7 8 9 const router = new VueRouter({ 10 // 注意:一旦采用了 history 模式,地址栏就没有 #,需要后台配置访问规则 11 mode: 'history', 12 routes: [ 13 { path: '/', redirect: '/home' }, 14 { path: '/home', component: Home }, 15 { name: 'search', path: '/search/:words?', component: Search }, 16 { path: '*', component: NotFound } 17 ] 18 }) 19 export default router
编程式导航 -用JS代码来进行跳转
① path 路径跳转
1 // 通过路由的path跳转 2 // 1、不带参数 3 this.$router.push('路由路径') 4 // 2、带query传参 5 this.$router.push('/路径?参数名1=参数值1&参数2=参数值2') 6 // 3、带query传参完整写法 7 this.$router.push({ 8 path: '路由路径', 9 query: { 10 参数名1: '参数值1', 11 参数名2: '参数值2' 12 } 13 }) 14 // 接受参数的方式依然是:$route.query.参数名 15 16 // 4、动态路由传参 17 this.$router.push('/路径/参数值1/参数2') 18 // 5、动态路由传参完整写法 19 this.$router.push({ 20 path: '/路径/参数值1/参数2' 21 }) 22 // 接受参数的方式依然是:$route.params.参数值
② name 命名路由跳转
1 // 前提: 路由规则配置新增name属性 2 { name: '路由名', path: '/path/xxx', component: XXX } 3 4 // 通过name进行跳转 5 this.$router.push({ 6 name: '路由名' 7 }) 8 9 // query传参 10 this.$router.push({ 11 name: '路由名字', 12 query: { 13 参数名1: '参数值1', 14 参数名2: '参数值2' 15 } 16 }) 17 // 动态路由传参 (需要配动态路由) 18 this.$router.push({ 19 name: '路由名字', 20 params: { 21 参数名: '参数值', 22 } 23 })
编程式导航示例
1、router/index.js
1 import Home from '@/views/Home' 2 import Search from '@/views/Search' 3 import NotFound from '@/views/NotFound' 4 import Vue from 'vue' 5 import VueRouter from 'vue-router' 6 Vue.use(VueRouter) // VueRouter插件初始化 7 8 // 创建了一个路由对象 9 const router = new VueRouter({ 10 // 注意:一旦采用了 history 模式,地址栏就没有 #,需要后台配置访问规则 11 mode: 'history', 12 routes: [ 13 { path: '/', redirect: '/home' }, 14 { path: '/home', component: Home }, 15 { name: 'search', path: '/search/:words?', component: Search }, 16 { path: '*', component: NotFound } 17 ] 18 }) 19 20 export default router
2、视图目录下
views/Home.vue
1 <template> 2 <div class="home"> 3 <div class="logo-box"></div> 4 <div class="search-box"> 5 <input v-model="inpValue" type="text"> 6 <button @click="goSearch">搜索一下</button> 7 </div> 8 <div class="hot-link"> 9 热门搜索: 10 <router-link to="/search/黑马程序员">黑马程序员</router-link> 11 <router-link to="/search/前端培训">前端培训</router-link> 12 <router-link to="/search/如何成为前端大牛">如何成为前端大牛</router-link> 13 </div> 14 </div> 15 </template> 16 17 <script> 18 export default { 19 name: 'FindMusic', 20 data () { 21 return { 22 inpValue: '' 23 } 24 }, 25 methods: { 26 goSearch () { 27 // 1. 通过路径的方式跳转 28 // (1) this.$router.push('路由路径') [简写] 29 // this.$router.push('路由路径?参数名=参数值') 30 // this.$router.push('/search') 31 // this.$router.push(`/search?key=${this.inpValue}`) 32 // this.$router.push(`/search/${this.inpValue}`) 33 34 // (2) this.$router.push({ [完整写法] 更适合传参 35 // path: '路由路径' 36 // query: { 37 // 参数名: 参数值, 38 // 参数名: 参数值 39 // } 40 // }) 41 // this.$router.push({ 42 // path: '/search', 43 // query: { 44 // key: this.inpValue 45 // } 46 // }) 47 // this.$router.push({ 48 // path: `/search/${this.inpValue}` 49 // }) 50 51 52 53 // 2. 通过命名路由的方式跳转 (需要给路由起名字) 适合长路径 54 // this.$router.push({ 55 // name: '路由名' 56 // query: { 参数名: 参数值 }, 57 // params: { 参数名: 参数值 } 58 // }) 59 this.$router.push({ 60 name: 'search', 61 // query: { 62 // key: this.inpValue 63 // } 64 params: { 65 words: this.inpValue 66 } 67 }) 68 } 69 } 70 } 71 </script> 72 73 <style> 74 .logo-box { 75 height: 150px; 76 background: url('@/assets/logo.jpeg') no-repeat center; 77 } 78 .search-box { 79 display: flex; 80 justify-content: center; 81 } 82 .search-box input { 83 width: 400px; 84 height: 30px; 85 line-height: 30px; 86 border: 2px solid #c4c7ce; 87 border-radius: 4px 0 0 4px; 88 outline: none; 89 } 90 .search-box input:focus { 91 border: 2px solid #ad2a26; 92 } 93 .search-box button { 94 width: 100px; 95 height: 36px; 96 border: none; 97 background-color: #ad2a26; 98 color: #fff; 99 position: relative; 100 left: -2px; 101 border-radius: 0 4px 4px 0; 102 } 103 .hot-link { 104 width: 508px; 105 height: 60px; 106 line-height: 60px; 107 margin: 0 auto; 108 } 109 .hot-link a { 110 margin: 0 5px; 111 } 112 </style>
views/Search.vue
1 <template> 2 <div class="search"> 3 <!-- 获取路由参数 --> 4 <p>搜索关键字: {{ $route.params.words }} </p> 5 <p>搜索结果: </p> 6 <ul> 7 <li>.............</li> 8 <li>.............</li> 9 <li>.............</li> 10 <li>.............</li> 11 </ul> 12 </div> 13 </template> 14 15 <script> 16 export default { 17 name: 'MyFriend', 18 created () { 19 // 在created中,获取路由参数 20 // this.$route.query.参数名 获取查询参数 21 // this.$route.params.参数名 获取动态路由参数 22 // console.log(this.$route.params.words); 23 } 24 } 25 </script> 26 <style> 27 .search { 28 width: 400px; 29 height: 240px; 30 padding: 0 20px; 31 margin: 0 auto; 32 border: 2px solid #c4c7ce; 33 border-radius: 5px; 34 } 35 </style>
3、根组件App.vue
1 <template> 2 <div id="app"> 3 <div class="link"> 4 <router-link to="/home">首页</router-link> 5 <router-link to="/search">搜索页</router-link> 6 </div> 7 <router-view></router-view> 8 </div> 9 </template> 10 11 <script> 12 export default {}; 13 </script> 14 15 <style scoped> 16 .link { 17 height: 50px; 18 line-height: 50px; 19 background-color: #495150; 20 display: flex; 21 margin: -8px -8px 0 -8px; 22 margin-bottom: 50px; 23 } 24 .link a { 25 display: block; 26 text-decoration: none; 27 background-color: #ad2a26; 28 width: 100px; 29 text-align: center; 30 margin-right: 5px; 31 color: #fff; 32 border-radius: 5px; 33 } 34 </style>
4、main.js
1 import Vue from 'vue' 2 import App from './App.vue' 3 import router from './router/index' 4 5 Vue.config.productionTip = false 6 7 new Vue({ 8 render: h => h(App), 9 router 10 }).$mount('#app')
路由守卫
1 import Vue from 'vue' 2 import VueRouter from 'vue-router' 3 import { getToken } from '@/utils/storage' 4 5 // 一级路由页面的导入 6 const Login = () => import('@/views/Login') 7 const Register = () => import('@/views/Register') 8 const Layout = () => import('@/views/Layout') 9 const Detail = () => import('@/views/Detail') 10 11 // 二级路由页面的导入 12 const Article = () => import('@/views/Article') 13 const Collect = () => import('@/views/Collect') 14 const Like = () => import('@/views/Like') 15 const User = () => import('@/views/User') 16 17 Vue.use(VueRouter) 18 19 const router = new VueRouter({ 20 routes: [ 21 { path: '/login', component: Login }, 22 { path: '/register', component: Register }, 23 { path: '/article/:id', component: Detail }, 24 { 25 path: '/', 26 component: Layout, 27 redirect: '/article', 28 children: [ 29 { path: '/article', component: Article }, 30 { path: '/like', component: Like }, 31 { path: '/collect', component: Collect }, 32 { path: '/user', component: User } 33 ] 34 } 35 ] 36 }) 37 38 // 白名单(就是一个数组,数组收录所有无需登录即可访问的页面) 39 const whiteList = ['/login', '/register'] 40 41 // 路由前置守卫 42 // 1. to 往哪去 43 // 2. from 从哪来 44 // 3. next 是否放行 next() 放行 next(路径) 拦截到某个页面 45 router.beforeEach((to, from, next) => { 46 const token = getToken() 47 if (token) { 48 // 如果有token,直接放行 49 next() 50 } else { 51 // 没有token的人,看看要去哪 52 // 判断访问的路径 to.path, 是否在白名单中 53 if (whiteList.includes(to.path)) { 54 next() 55 } else { 56 next('/login') 57 } 58 } 59 }) 60 61 export default router
组件缓存 keep-alive