💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] ## 1. 什么是路由 1. 对于普**通的网站**,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源; 2. 对于**单页面应用程序**来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时,hash有一个特点:HTTP请求中不会包含hash相关的内容;**所以,单页面程序中的页面跳转主要用hash实现;** 3. **在单页面应用程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由);** ## 2. 在 vue 中使用 vue-router ![](https://img.kancloud.cn/54/d9/54d9f51ad937286210f434cc84755a5c_397x207.png) url 变化: ![](https://img.kancloud.cn/2c/9d/2c9d1854bca7d63f067ee1a2e8affdff_783x61.png) ![](https://img.kancloud.cn/95/2d/952d2b28758c58aecc6e33e05f384686_809x76.png) 1. 导入 vue-router 组件类库: ~~~ <script src="./lib/vue-router-2.7.0.js"></script> ~~~ 2. 使用 router-link 组件来导航 ~~~ <!-- 2. 使用 router-link 组件来导航 --> <router-link to="/login">登录</router-link> <router-link to="/register">注册</router-link> ~~~ 3. 使用 router-view 组件来显示匹配到的组件 **路由控制这里的显示** ~~~ <!-- 3. 使用 router-view 组件来显示匹配到的组件 --> <router-view></router-view> ~~~ 4. 创建使用`Vue.extend`创建组件 ~~~   // 4.1 使用 Vue.extend 来创建登录组件   var login = Vue.extend({     template: '<h1>登录组件</h1>'   }); ​   // 4.2 使用 Vue.extend 来创建注册组件   var register = Vue.extend({     template: '<h1>注册组件</h1>'   }); ~~~ 5. 创建一个路由 router 实例,通过 routers 属性来定义路由匹配规则 ~~~ // 5. 创建一个路由 router 实例,通过 routers 属性来定义路由匹配规则   var router = new VueRouter({     routes: [       { path: '/login', component: login },       { path: '/register', component: register }     ]   }); ~~~ 6. 使用 router 属性来使用路由规则 ~~~ // 6. 创建 Vue 实例,得到 ViewModel   var vm = new Vue({     el: '#app',     router: router // 使用 router 属性来使用路由规则   }); ~~~ 整体 ``` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="./lib/vue-2.4.0.js"></script> <!-- 1. 安装 vue-router 路由模块 --> <script src="./lib/vue-router-3.0.1.js"></script> <style> .router-link-active, .myactive { color: red; font-weight: 800; font-style: italic; font-size: 80px; text-decoration: underline; background-color: green; } .v-enter, .v-leave-to { opacity: 0; transform: translateX(140px); } .v-enter-active, .v-leave-active { transition: all 0.5s ease; } </style> </head> <body> <div id="app"> <!-- <a href="#/login">登录</a> --> <!-- <a href="#/register">注册</a> --> <!-- router-link 默认渲染为一个a 标签 --> <router-link to="/login" tag="span">登录</router-link> <router-link to="/register">注册</router-link> <!-- 这是 vue-router 提供的元素,专门用来 当作占位符的,将来,路由规则,匹配到的组件,就会展示到这个 router-view 中去 --> <!-- 所以: 我们可以把 router-view 认为是一个占位符 --> <transition mode="out-in"> <router-view></router-view> </transition> </div> <script> // 组件的模板对象 var login = { template: '<h1>登录组件</h1>' } var register = { template: '<h1>注册组件</h1>' } /* Vue.component('login', { template: '<h1>登录组件</h1>' }) */ // 2. 创建一个路由对象, 当 导入 vue-router 包之后,在 window 全局对象中,就有了一个 路由的构造函数,叫做 VueRouter // 在 new 路由对象的时候,可以为 构造函数,传递一个配置对象 var routerObj = new VueRouter({ // route // 这个配置对象中的 route 表示 【路由匹配规则】 的意思 routes: [ // 路由匹配规则 // 每个路由规则,都是一个对象,这个规则对象,身上,有两个必须的属性: // 属性1 是 path, 表示监听 哪个路由链接地址; // 属性2 是 component, 表示,如果 路由是前面匹配到的 path ,则展示 component 属性对应的那个组件 // 注意: component 的属性值,必须是一个 组件的模板对象, 不能是 组件的引用名称; // { path: '/', component: login }, { path: '/', redirect: '/login' }, // 这里的 redirect 和 Node 中的 redirect 完全是两码事 { path: '/login', component: login }, { path: '/register', component: register } ], linkActiveClass: 'myactive' }) // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {}, router: routerObj // 将路由规则对象,注册到 vm 实例上,用来监听 URL 地址的变化,然后展示对应的组件 }); </script> </body> </html> ``` ## router-view的name属性 通过名称,将组件渲染到对应的router-view上 1. 通过name属性,标识router-view,不写默认就是default ``` <router-view></router-view> <router-view name="router1"></router-view> ``` 2. components指定多个渲染,而不是component ``` routes: [ // 路由匹配规则 { path: '/', redirect: '/login' }, // 这里的 redirect 和 Node 中的 redirect 完全是两码事 { path: '/login', components: {default:login,router1:t1} }, { path: '/register', components: {default:register,router2:t2} } ], ``` 完整 ``` <body> <div id="app"> <router-link to="/login" tag="span">登录</router-link> <router-link to="/register">注册</router-link> <router-view></router-view> <router-view name="router1"></router-view> <router-view name="router2"></router-view> </div> <script> // 组件的模板对象 var login = { template: '<h1>登录组件</h1>' } var register = { template: '<h1>注册组件</h1>' } var t1 = { template: '<h1>router1我来了</h1>' } var t2 = { template: '<h1>router2我来了</h1>' } var routerObj = new VueRouter({ routes: [ // 路由匹配规则 { path: '/', redirect: '/login' }, // 这里的 redirect 和 Node 中的 redirect 完全是两码事 { path: '/login', components: {default:login,router1:t1} }, { path: '/register', components: {default:register,router2:t2} } ], linkActiveClass: 'myactive' }) // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {}, router: routerObj // 将路由规则对象,注册到 vm 实例上,用来监听 URL 地址的变化,然后展示对应的组件 }); </script> </body> ``` ![](https://img.kancloud.cn/83/ae/83ae57650a03cb436e0097c57f2fe236_652x382.png) 点击注册 ![](https://img.kancloud.cn/23/55/2355588b895f7dc7a552673996133a3c_655x301.png) ## 设置路由高亮 ## 设置路由切换动效 **## 在路由规则中定义参数** **1.指定实参** ~~~ <router-link to="/login/12/ls">登录</router-link> ~~~ **2. 通过 `this.$route.params`来获取路由中的参数**: ~~~ var login = { template: '<h1>登录 --- {{ $route.params.id }} --- {{ $route.params.name }}</h1>', data(){ return { msg: '123' } }, created(){ // 组件的生命周期钩子函数 console.log(this.$route.params.id) } } ~~~ **3. 在规则中定义路径对应的参数** 在router对象中指定id和name ~~~ var router = new VueRouter({ routes: [ { path: '/login/:id/:name', component: login }, { path: '/register', component: register } ] }) ~~~ ## **路由路径中传递参数** ~~~ 如果在路由中,使用 查询字符串,给路由传递参数,则 不需要修改 路由规则的 path 属性 ~~~ <router-link to="/login?id=10&name=zs">登录</router-link> ~~~ var login = { template: '<h1>登录 --- {{ $route.query.id }} --- {{ $route.query.name }}</h1>', data(){ return { msg: '123' } }, ~~~ 完整代码 ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="./lib/vue-2.4.0.js"></script> <script src="./lib/vue-router-3.0.1.js"></script> </head> <body> <div id="app"> <!-- 如果在路由中,使用 查询字符串,给路由传递参数,则 不需要修改 路由规则的 path 属性 --> <router-link to="/login?id=10&name=zs">登录</router-link> <router-link to="/register">注册</router-link> <router-view></router-view> </div> <script> var login = { template: '<h1>登录 --- {{ $route.query.id }} --- {{ $route.query.name }}</h1>', data(){ return { msg: '123' } }, created(){ // 组件的生命周期钩子函数 // console.log(this.$route) // console.log(this.$route.query.id) } } var register = { template: '<h1>注册</h1>' } var router = new VueRouter({ routes: [ { path: '/login', component: login }, { path: '/register', component: register } ] }) // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {}, // router: router router }); </script> </body> </html> ~~~ ## **使用 `children` 属性实现路由嵌套** ![](https://img.kancloud.cn/60/84/6084ee181c1034241bf04f6c06666c17_1027x359.png) ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="./lib/vue-2.4.0.js"></script> <script src="./lib/vue-router-3.0.1.js"></script> </head> <body> <div id="app"> <router-link to="/account">Account</router-link> <! -- 第一个router站位 --> <router-view></router-view> </div> <template id="tmpl"> <div> <h1>这是 Account 组件</h1> <router-link to="/account/login">登录</router-link> <router-link to="/account/register">注册</router-link> <! -- 第二个router站位 子router --> <router-view></router-view> </div> </template> <script> // 组件的模板对象 var account = { template: '#tmpl' } var login = { template: '<h3>登录</h3>' } var register = { template: '<h3>注册</h3>' } var router = new VueRouter({ routes: [ { path: '/account', component: account, // 使用 children 属性,实现子路由,同时,子路由的 path 前面,不要带 / ,否则永远以根路径开始请求,这样不方便我们用户去理解URL地址 children: [ { path: 'login', component: login }, { path: 'register', component: register } ] } // { path: '/account/login', component: login }, // { path: '/account/register', component: register } ] }) // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {}, router }); </script> </body> </html> ~~~ ## **路由前操作router.beforeEach** >  在前端路由跳转中,路由跳转前都是会经过beforeEach,而beforeEach可以通过next来控制到底去哪个路由。利用这一特点,可以做发送请求时的操作:例如:权限校验(是否登录、页面是否存在) beforeEach需要三个参数:  **to: Route**: 即将要进入的目标路由对象         **from: Route**: 当前导航正要离开的路由         **next: Function**: 一定要调用该方法来 **resolve** 这个钩子。执行效果依赖 next 方法的调用参数。 代码: ``` router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.requireAuth)){ // 判断该路由是否需要登录权限 if (token) { // 判断当前的token是否存在 next(); } else { next({ path: '/login', // 将跳转的路由path作为参数,登录成功后跳转到该路由(to原来的路由对象) query: {redirect: to.fullPath} }) } } else { next(); } }); ``` 但是除了用户请求特定页面时(拦截是否登录),登录后继续请求这个页面。正常登录时不需要跳转。 ``` if(this.$route.query.redirect){ let redirect = this.$route.query.redirect; this.$router.push(redirect); }else{ this.$router.push('/'); } ``` ## **router.push** `router.push(location) `: 用来进行页面跳转 * 除了使用 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。  * 想要导航到不同的 URL,则使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。当你点击时,这个方法会在内部调用,所以说,点击 等同于调用 router.push(…)。 声明式: `<router-link :to="..."> ` 编程式:router.push(...)  该方法的参数可以是一个字符串路径,或者一个描述地址的对象。 ~~~ // 字符串 router.push('home') // 对象 this.$router.push({path: '/login?url=' + this.$route.path}); // 命名的路由 router.push({ name: 'user', params: { userId: 123 }}) // 带查询参数,变成/backend/order?selected=2 this.$router.push({path: '/backend/order', query: {selected: "2"}}); // 设置查询参数 this.$http.post('v1/user/select-stage', {stage: stage}) .then(({data: {code, content}}) => { if (code === 0) { // 对象 this.$router.push({path: '/home'}); }else if(code === 10){ // 带查询参数,变成/login?stage=stage this.$router.push({path: '/login', query:{stage: stage}}); } }); // 设计查询参数对象 let queryData = {}; if (this.$route.query.stage) { queryData.stage = this.$route.query.stage; } if (this.$route.query.url) { queryData.url = this.$route.query.url; } this.$router.push({path: '/my/profile', query: queryData}); ~~~ ### replace > 类型: boolean  > 默认值: false  设置 replace 属性的话,当点击时,会调用 router.replace() 而不是 router.push(),于是导航后不会留下 history 记录。即使点击返回按钮也不会回到这个页面。  //加上replace: true后,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。 ~~~ this.$router.push({path: '/home', replace: true}) //如果是声明式就是像下面这样写: <router-link :to="..." replace></router-link> // 编程式: router.replace(...) ~~~ # 缓存 tab切换,缓存已渲染的数据,不会触发生命mounted 页面现在默认有缓存机制,如果不想缓存,添加meta: { notCache: true },并且name属性要和vue页面 export default 里的name属性对应