Vue-Router 基础
简介
Vue-Router
是用来将一个Vue
程序的多个页面进行路由的。比如一个Vue
程序(或者说一个网站)有登录
、注册
、首页
等模块,那么我们就可以定义/login
、/register
、/
来映射每个模块。
安装
通过script
加载进来:
使用CDN
:
加载最新版的:
1 | <script src= "https://unpkg.com/vue-router/dist/vue-router.js" ></script> |
加载指定版本的:
1 | <script src= "https://unpkg.com/vue-router@3.0.7/dist/vue-router.js" ></script> |
下载到本地:
1 | <script src= "../../lib/vue-router.js" ></script> |
通过npm
安装:
1 | npm install vue-router |
文档
官方文档:https://router.vuejs.org/zh/
github地址:https://github.com/vuejs/vue-router
基本使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" > <title>vuedemo</title> <script src= "https://cdn.jsdelivr.net/npm/vue" ></script> <script src= "https://unpkg.com/vue-router/dist/vue-router.js" ></script> </head> <body> <div id= "app" > <div class = "container-fluid" > <div class = "row" > <div class = "col-md-8 col-md-offset-2" > <ul class = "nav nav-tabs" > <li role= "presentation" class = "active" > <router-link to= "/find" >发现音乐</router-link> </li> <li role= "presentation" > <router-link to= "/my" >我的音乐</router-link> </li> <li role= "presentation" > <router-link to= "/friend" >朋友</router-link> </li> </ul> <!-- 路由出口 --> <!-- 路由匹配到的组件将渲染在这里 --> <router-view></router-view> </div> </div> </div> </div> <script> var find = Vue.extend({template: "<h1>发现音乐</h1>" }); var my = Vue.extend({template: "<h1>我的音乐</h1>" }); var friend = Vue.extend({template: "<h1>朋友</h1>" }); var routes = [ {path: "/find" , component: find}, {path: "/my" , component: my}, {path: "/friend" , component: friend}, {path: "/" , component: find} ]; const router = new VueRouter({routes}); new Vue({router}).$mount( "#app" ); </script> </body> </html> |
解释:
- 在
vue-router
中,使用<router-link>
来加载链接,然后使用to
表示跳转的链接。vue-router
最终会把<router-link>
渲染成<a>
标签。 <router-view>
是路由的出口,也就是相应url
下的代码会被渲染到这个地方来。Vue.extend
是用来加载模板的。routes
是定义一个url
与组件的映射,这个就是路由。VueRouter
创建一个路由对象。$mount
是挂载到哪个组件上。
动态路由
在路由中有一些参数是会变化的,比如查看某个用户的个人中心,那肯定需要在url
中加载这个人的id
,这时候就需要用到动态路由了。
示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" > <title>vuedemo</title> <script src= "https://cdn.jsdelivr.net/npm/vue" ></script> <script src= "https://unpkg.com/vue-router/dist/vue-router.js" ></script> </head> <body> <div id= 'app' > <ul> <li> <router-link to= "/" >首页</router-link> </li> <li> <router-link to= "/profile/123" >个人中心</router-link> </li> </ul> <router-view></router-view> </div> <script> let index = Vue.extend({template: "<h1>首页</h1>" }); let profile = Vue.extend({ template: "<h1>个人中心:{{$route.params.userid}}</h1>" , mounted() { console.log( this .$route); console.log( this .$router); } }); let router = new VueRouter({ routes: [ {path: "/" , component: index}, {path: "/profile/:userid" , component: profile}, ] }); new Vue({ el: '#app' , router }) </script> </body> </html> |
解释:
:userid
:动态的参数。this.$route.params
:这个里面记录了路由中的参数。
组件复用
当使用路由参数时,例如从/user/foo
导航到/user/bar
,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。
复用组件时,想对路由参数的变化作出响应的话,你可以简单地watch(监测变化)
$route
对象:
1 2 3 4 5 6 7 8 | const User = { template: '...' , watch: { '$route' (to, from ) { // 对路由变化作出响应... } } } |
或者是使用导航守卫:
1 2 3 4 5 6 7 | const User = { template: '...' , beforeRouteUpdate (to, from , next) { // react to route changes... // don't forget to call next() } } |
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" > <title>vuedemo</title> <script src= "https://cdn.jsdelivr.net/npm/vue" ></script> <script src= "https://unpkg.com/vue-router/dist/vue-router.js" ></script> </head> <body> <div id= 'app' > <ul> <li> <router-link to= "/profile/张三" >张三的个人中心</router-link> </li> <li> <router-link to= "/profile/李四" >李四的个人中心</router-link> </li> </ul> <router-view></router-view> </div> <script> let index = Vue.extend({ template: "<h1>首页</h1>" }); let profile = Vue.extend({ template: "<h1>个人中心:{{$route.params.userid}}</h1>" , mounted() { console.log( this .$route. params .userid); }, // watch:{ // "$route": function(to,from){ // console.log("to:",to); // console.log("from:",from); // } // } beforeRouteUpdate: function (to, from , next) { console.log( "to:" , to); console.log( "from:" , from ); // next() } }); let router = new VueRouter({ routes: [ {path: "/" , component: index}, {path: "/profile/:userid" , component: profile} ] }); new Vue({ el: '#app' , router }) </script> </body> </html> |
匹配404错误
在路由规则中,*
代表的是任意字符。所以只要在路由的最后添加一个*
路由,那么以后没有匹配到的url
都会被导入到这个视图中。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" > <title>vuedemo</title> <script src= "https://cdn.jsdelivr.net/npm/vue" ></script> <script src= "https://unpkg.com/vue-router/dist/vue-router.js" ></script> </head> <body> <div id= 'app' > <router-view></router-view> </div> <script> let index = Vue.extend({ template: "<h1>首页</h1>" }); let aboutus = Vue.extend({ template: "<h1>关于我们</h1>" }); let profile = Vue.extend({ template: "<h1>个人中心:{{$route.params.userid}}</h1>" , mounted() { if ( this .$route. params .userid != '123' ) { this .$router.replace( "/404" ) } }, watch: { "$route" : function (to, from ) { // to // 从to中提取userid,然后判断是不是等于123,如果不等于,那就跳转到404 // 从to中提取userid,然后发送给服务器,服务器判断存不存在,如果不存在,同样跳转到404 } } }); let notfound = Vue.extend({ template: "<h1>404页面没找到</h1>" , }); let router = new VueRouter({ routes: [ {path: "/" , component: index}, {path: "/aboutus" , component: aboutus}, {path: "/profile/:userid" , component: profile}, {path: "/404" , component: notfound}, {path: "*" , component: notfound} ] }); new Vue({ el: '#app' , router: router }) </script> </body> </html> |
嵌套路由
有时候在路由中,主要的部分是相同的,但是下面可能是不同的。比如访问用户的个人中心是/user/111/profile/
,查看用户发的贴子是/user/111/posts/
等。这时候就需要使用到嵌套路由。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | const router = new VueRouter({ routes: [ { path: '/user/:id' , component: User, children: [ { // 当 /user/:id/profile 匹配成功, // UserProfile 会被渲染在 User 的 <router-view> 中 path: 'profile' , component: UserProfile }, { // 当 /user/:id/posts 匹配成功 // UserPosts 会被渲染在 User 的 <router-view> 中 path: 'posts' , component: UserPosts } ] } ] }); |
编程式导航
之前我们学习了使用<router-link>
可以在用户点击的情况下进行页面更新。但有时候我们想要在js
中手动的修改页面的跳转,这时候就需要使用编程式导航了。
$router.push
跳转:
想要导航到不同的URL
,则使用router.push
方法。这个方法会向history
栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的URL
。
当你点击<router-link>
时,这个方法会在内部调用,所以说,点击<router-link :to="...">
等同于调用router.push(...)
。
声明式 | 编程式 |
---|---|
<router-link :to="..."> |
router.push(...) |
1 2 3 4 5 6 7 8 9 10 | // 字符串<br>router.push('home') // 对象 router.push({ path: 'home' }) // 命名的路由 router.push({ name: 'user' , params : { userId: '123' }}) // 带查询参数,变成 /register?plan=private router.push({ path: 'register' , query: { plan: 'private' }}) |
注意:如果提供了path
,params
会被忽略,上述例子中的query
并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的name
或手写完整的带有参数的path
:
1 2 3 4 5 | const userId = '123' router.push({ name: 'user' , params : { userId }}) // -> /user/123 router.push({ path: `/user/${userId}` }) // -> /user/123 // 这里的 params 不生效 router.push({ path: '/user' , params : { userId }}) // -> /user |
router.replace(location, onComplete?, onAbort?)
:
跟 router.push 很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。
router.go(n)
:
这个方法的参数是一个整数,意思是在history
记录中向前或者后退多少步,类似 window.history.go(n)
。
1 2 3 4 5 6 7 8 9 10 11 12 | // 在浏览器记录中前进一步,等同于 history.forward() router.go(1) // 后退一步记录,等同于 history.back() router.go(-1) // 前进 3 步记录 router.go(3) // 如果 history 记录不够用,那就默默地失败呗 router.go(-100) router.go(100) |
命名路由
有时候,通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。你可以在创建Router
实例的时候,在routes
配置中给某个路由设置名称。
1 2 3 4 5 6 7 8 9 | const router = new VueRouter({ routes: [ { path: '/user/:userId' , name: 'user' , component: User } ] }) |
要链接到一个命名路由,可以给router-link
的to
属性传一个对象:
1 | <router-link :to= "{ name: 'user', params: { userId: 123 }}" >User</router-link> |
这跟代码调用 router.push() 是一回事:
1 | router.push({ name: 'user' , params : { userId: 123 }}) |
命名视图
有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有sidebar
(侧导航) 和main
(主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果router-view
没有设置名字,那么默认为default
。
1 2 3 | <router-view class = "view one" ></router-view> <router-view class = "view two" name= "a" ></router-view> <router-view class = "view three" name= "b" ></router-view> |
一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components
配置 (带上s
):
1 2 3 4 5 6 7 8 9 10 11 12 | const router = new VueRouter({ routes: [ { path: '/' , components: { default : Foo, a: Bar, b: Baz } } ] }) |
重定向和别名
重定向也是通过routes
配置来完成,下面例子是从/a
重定向到/b
:
1 2 3 4 5 | const router = new VueRouter({ routes: [ { path: '/a' , redirect: '/b' } ] }) |
重定向的目标也可以是一个命名的路由:
1 2 3 4 5 | const router = new VueRouter({ routes: [ { path: '/a' , redirect: { name: 'foo' }} ] }) |
“重定向”的意思是,当用户访问/a
时,URL
将会被替换成/b
,然后匹配路由为/b
,那么“别名”又是什么呢?
/a
的别名是/b
,意味着,当用户访问/b
时,URL
会保持为/b
,但是路由匹配则为 /a
,就像用户访问/a
一样。
上面对应的路由配置为:
1 2 3 4 5 | const router = new VueRouter({ routes: [ { path: '/a' , component: A, alias: '/b' } ] }) |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了