1、vue router 的入门案例
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> </style> <script src="./lib/vue.js"></script> <script src="./lib/vue-router.js"></script> <script> window.onload = function () { let rout = new VueRouter({ routes: [ //传参时,注意是$route.params { path: '/user/:id', component: { template: '<div>this is user,id is {{$route.params.id}}</div>', beforeRouteUpdate(to, from, next) { console.log('to:', to); console.log(from); //如果没有next(),那么就不会往下走 next(); } } } ] }); let VM = new Vue({ el: '#container', router: rout, methods: { forward() { //前进 this.$router.go(1); }, backward() { //后退 this.$router.go(-1); }, push() { //跳转 this.$router.push('/user/111'); } } }) } </script> </head> <body> <div id="container"> <input type="button" value="前进" @click="forward"> <input type="button" value="后退" @click="backward"> <input type="button" value="跳转" @click="push"><br/> <router-link to="/user/111">user111</router-link> <router-link to="/user/222">user222</router-link> <router-link to="/user/333">user333</router-link> <router-view></router-view> </div> </body> </html>
注意:在vuerouter里面用的component未必要在vue里面注册组件,可以独立的存在
2、子路由的使用
a、子路由使用一 => 在路由页面里面定义子路由
<body> <div id="container"> <router-link to="/">first</router-link> <router-link to="/second">second</router-link> <router-view></router-view> </div> <template id="first"> <div> <h1>this is first</h1> <!--在这个子路由里面用的就是二级路径而不是全路径--> <router-link to="/">aaa</router-link> <router-link to="/bbb">bbb</router-link> <router-view></router-view> </div> </template> <script src="./vue.js"></script> <script src="./vue-router.js"></script> <script> let first = { template: '#first' }; let second = { template: '<div>this is second</div>' }; let fourth = { template: '<div>this is fourth</div>' }; let fifth = { template: '<div>this is fifth</div>' }; let routes = [ { path: '/', component: first, children: [ //注意子路由里面children接收的是一个数组,并且里面的子路由不能够带'/'符号 {path:'', component: fourth}, {path: 'bbb', component: fifth} ] }, {path: '/second', component: second} ]; let router = new VueRouter({ routes }); let app = new Vue({ el: '#container', router }); </script>
export default [ { path: '/', name: 'home', component: Home }, { path: '/about', name: 'about', component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') }, { path: '/check', component: check, redirect: '/second', children: [ { path: '/first', component: first }, { path: '/second', component: second } ] } ]
b、子路由的使用二 => 在路由页面外面定义子路由标签
<body> <div id="container"> <router-link to="/first">first</router-link> <router-link to="/first/aaa">aaa</router-link> <!--页面会转到first页面下的aaa标签,注意这里的写法--> <router-link to="/first/bbb">bbb</router-link> <!--页面会转到first页面下的bbb标签,注意这里的写法--> <router-link to="/second">second</router-link> <router-view></router-view> </div> <template id="first"> <div> <h1>this is first</h1> <router-view></router-view> </div> </template> <script src="./vue.js"></script> <script src="./vue-router.js"></script> <script> let first = { template: '#first' }; let second = { template: '<div>this is second</div>' }; let fourth = { template: '<div>this is fourth</div>' }; let fifth = { template: '<div>this is fifth</div>' }; let routes = [ { path: '/first', component: first, children: [ //注意子路由里面children接收的是一个数组,并且里面的子路由不能够带'/'符号 {path:'aaa', component: fourth}, {path: 'bbb', component: fifth} ] }, {path: '/second', component: second} ]; let router = new VueRouter({ routes }); let app = new Vue({ el: '#container', router }); </script> </body>
3、路由参数的传递
路由接收参数需要用到$route,注意这里是$route而不是$router;
<body> <div id="container"> <!-- <router-link to="/first">first</router-link>传参可以用以下的写法--> <router-link :to="{name: 'aaa', params: {username: 'AAA', id: 123}}">first</router-link> <!--接收相应的数据用$route.name, $route.params.username或者$route.params.id--> <router-link to="/second">second</router-link> <router-view></router-view> </div> <script src="./vue.js"></script> <script src="./vue-router.js"></script> <script> let first = { template: '<div>this is first content--{{$route.params.username}}---{{$route.params.id}} <input type="button" value="btn" @click="check"></div>', methods: { check() { console.group('相应的参数'); console.log(this.$route.params.username, this.$route.params.id); //注意这里的this.$route要和this.$router区分开 console.groupEnd(); } } }; let second = { template: '<div>this is second content</div>' }; let routes = [ {path: '/first', name: 'aaa', component: first}, {path: '/second', name: 'bbb', component: second} ]; let app = new Vue({ el: '#container', router: new VueRouter({routes}) }); </script> </body>
通过url进行传值
<body> <div id="container"> <router-link to="/first/haha/123">first</router-link> <router-link to="/second/yes/111">second</router-link> <router-view></router-view> </div> <script src="./vue.js"></script> <script src="./vue-router.js"></script> <script> let first = { template: '<div>this is first content, str的值为{{$route.params.str}}, id的值为{{$route.params.id}}</div>', }; let second = { template: '<div>this is second content</div>' }; let routes = [ {path: '/first/:str/:id(\d+)', name: 'aaa', component: first}, //当地址不完全匹配的时候不显示,只有完全匹配的时候会显示 #/first/haha/34 {path: '/second/:str/:id', name: 'bbb', component: second} //如果需要添加正则匹配的时候,可以用(\d+)或者其他方式进行添加 ]; let app = new Vue({ el: '#container', router: new VueRouter({routes}) }); </script> </body>
通过组件传值的方式传值
{ path: '/check', component: check, // redirect: '/first/yf', children: [ { path: '/first/:name', name: 'first', component: first }, { path: '/second', component: second } ], // props: true // 方式一 这种情况假如路由下是/check/:name, 那么会自动的把name进行组件传值的 // props: { // 方式二 // name: 'test' // }, props: route => { // 方式三 return { name: 'check' } } }
那么接收和组件的接收方式是一样的, 在路由的view中写如下代码进行接收
export default { props: { name: { type: String, default: '' } }, methods: { getName () { console.log(this.name); } } }
路由中还可以定义meta进行传值
4、单页面多路由区域
多个路由区域是指存在多个router-view的时候需要在router-view上声明name
<body> <div id="container"> <router-link :to="{name: 'aaa'}">first</router-link> <router-link :to="{name: 'bbb'}">second</router-link> <router-view></router-view> <router-view name="part"></router-view> <!--存在多个router-view的时候要指定name--> <router-view name="block"></router-view> </div> <script src="./vue.js"></script> <script src="./vue-router.js"></script> <script> let first = { template: '<div>this is first content</div>', }; let second = { template: '<div>this is second content</div>' }; let routes = [ {path: '/first', name: 'aaa', components: { default: first, //指定默认的router-view的组件,即没有声明name的router-view part: second, //指定名字为part的router-view的组件 block: first //指定名字为block的router-view的组件 } }, {path: '/second', name: 'bbb', components: { default: second, part: first, block: second } } ]; let app = new Vue({ el: '#container', router: new VueRouter({routes}) }); </script> </body>
注意,当存在多个router-view的时候,里面的component需要转变为components
5、路由的重定向
正常的重定向,可以在route里面加配redirect这个配置,如果需要动态调用,可以用$router.push(路由),具体例子如下:
<body> <div id="container"> <router-link to="/first/haha/123">first</router-link> <router-link to="/second/yes/111">second</router-link> <router-view></router-view> </div> <script src="./vue.js"></script> <script src="./vue-router.js"></script> <script> let first = { template: '<div>this is first content, str的值为{{$route.params.str}}, id的值为{{$route.params.id}}</div>', }; let second = { template: '<div>this is second content <input type="button" value="btn" @click="check"></div>', methods: { check() { this.$router.push('/first/haha/111', function(router) { console.log(arguments); //动态的转到某个路由上,可以用push这个方法 }); } } }; let routes = [ {path: '/first/:str/:id(\d+)', name: 'aaa', component: first}, {path: '/second/:str/:id', name: 'bbb', component: second, redirect: '/first/yu/111'}, //如果需要添加正则匹配的时候,可以用(\d+)或者其他方式进行添加 // {path: '/second/:str/:id', name: 'bbb', component: second, redirect: {name: 'aaa', params: {str: 'get', id: 111}}} //如果需要添加正则匹配的时候,可以用(\d+)或者其他方式进行添加 ]; let app = new Vue({ el: '#container', router: new VueRouter({routes}) }); </script> </body>
6、alias 别名的用法
<body> <div id="container"> <router-link to="/">first</router-link> <router-link :msg=msg to="/bill">bill</router-link> <!--利用别名进行跳转--> <router-link :msg=msg to="/haha">second</router-link> <router-view></router-view> </div> <script src="./vue.js"></script> <script src="./vue-router.js"></script> <script> let first = { template: '<div>this is first content, str的值为{{$route.params.str}}, id的值为{{$route.params.id}}</div>', }; let second = { template: '<div>this is second content</div>', }; let routes = [ {path: '/', name: 'aaa', component: first, alias: '/haha'}, {path: '/second', name: 'bbb', component: second, alias: '/bill'}, //添加别名后,访问/bill可以跳转到/second这个路径下 ]; let app = new Vue({ el: '#container', data: { msg: 'this is msg' }, router: new VueRouter({routes}) }); </script> </body>
7、路由过渡动画
添加路由的过渡动画需要在router-view外层包一层的transition标签,如下例:
<style> .fade-enter { /*进入过渡的开始状态,元素插入时生效,只应用一帧后立刻删除*/ opacity: 0; } .fade-enter-active { /*进入过渡的结束状态,元素插入时生效,在过渡过程完成后删除*/ transition: opacity 0.5s; } .fade-leave { /*离开过渡的开始状态,元素被删除时触发,只应用一帧后立刻删除*/ opacity: 1; } .fade-leave-active { /*离开过渡的结束状态,元素被删除时生效,离开过渡完成后被删除*/ opacity: 0; transition: opacity 0.5s } </style> </head> <body> <div id="container"> <router-link to="/first">first</router-link> <router-link to="/second">second</router-link> <transition name="fade" mode="out-in"> <!--默认的mode是in-out表示进入后,再删除--> <router-view></router-view> </transition> </div> <script src="./vue.js"></script> <script src="./vue-router.js"></script> <script> let first = { template: '<div>this is first content</div>', }; let second = { template: '<div>this is second content</div>', }; let routes = [ {path: '/first', name: 'aaa', component: first}, {path: '/second', name: 'bbb', component: second}, ]; let app = new Vue({ el: '#container', data: { msg: 'this is msg' }, router: new VueRouter({routes}) }); </script> </body>
8、history模式与配置404页面
a、在配置路由后,访问路由的时候,在地址栏中会显示#相当符号,那么为了美观,可以选择另外一种显示方式history, router里的模式有hash与history,默认是hash
b、如果访问了未知页面,为了友好的用户体验,可以配置404页面
<body> <div id="container"> <router-link to="/first">first</router-link> <router-link to="/second">second</router-link> <router-view></router-view> </div> <script src="./vue.js"></script> <script src="./vue-router.js"></script> <script> let first = { template: '<div>this is first content</div>', }; let second = { template: '<div>this is second content</div>', }; let error = { template: '<div>404, 没有找到相关的页面</div>' }; let routes = [ {path: '/first', name: 'aaa', component: first}, {path: '/second', name: 'bbb', component: second}, {path:'*', component: error} //配置404页面的时候,path为*号 ]; let app = new Vue({ el: '#container', data: { msg: 'this is msg' }, router: new VueRouter({mode:'history', routes}) //注意使用history必需要在服务器的环境下进行配置,否则会报错 }); </script> </body>
9、路由中的钩子函数
有两种方式:一种方式,在component里面进行写beforeRouterEnter, beforeRouterLeave, 第二种方式, 在route里面定义相当的方法 beforeEnter,例子如下:
<body> <div id="container"> <router-link to="/first">first</router-link> <router-link to="/second">second</router-link> <router-view></router-view> </div> <script src="./vue.js"></script> <script src="./vue-router.js"></script> <script> let first = { template: '<div>this is first content</div>', }; let second = { template: '<div>{{msg}}</div>', data: function() { return { 'msg': 'this is second content' } }, //方法一, 写在component里面可以触发相应的钩子 beforeRouteEnter(to, from, next){ console.log('beforeRouteEnter', arguments); next() }, beforeRouteLeave(to, from ,next) { console.log('beforeRouteLeave', arguments); next() } }; //方法二:在router里面写钩子 let routes = [ { path: '/first', name: 'aaa', component: first, beforeEnter(to, from, next) { //to表示来的路由,from表示目标路由,next表示执行跳转的函数 next(); //next表示执行跳转的动作,next里面接收一个参数,如果是true表示执行跳转,如果是false则表示不跳转 } }, {path: '/second', name: 'bbb', component: second}, ]; let app = new Vue({ el: '#container', data: { msg: 'this is msg' }, router: new VueRouter({mode: 'hash', routes}) //注意使用history必需要在服务器的环境下进行配置,否则会报错 }); </script> </body>
beforeEach可以做登录页面的跳转 router.beforeEach() => {}, next()的括号里可以传boolean 也可以传string, 也可以传route对象实例,如{ name: 'home' } 等
let router = new VueRouter({ routes }); router.beforeEach((to, from, next) => { if (to.name === 'about') { next({ name: 'home' }) } else { next(); } }) export default router;
10、编程式导航
<body> <div id="container"> <div> <input type="button" value="前进" @click="forward"> <input type="button" value="后退" @click="back"> <input type="button" value="向后跳2" @click="skip"> <input type="button" value="回首页" @click="gohome"> </div> <router-link to="/first">first</router-link> <router-link to="/second">second</router-link> <router-view></router-view> </div> <script src="./vue.js"></script> <script src="./vue-router.js"></script> <script> let first = { template: '<div>this is first content</div>', }; let second = { template: '<div>this is second content</div>', }; let routes = [ {path: '/first', name: 'aaa', component: first}, {path: '/second', name: 'bbb', component: second}, ]; let app = new Vue({ el: '#container', data: { msg: 'this is msg' }, methods: { forward() { this.$router.forward(); //向前跳转 }, back() { this.$router.back(); //向后跳转 }, skip() { this.$router.go(-2); //跳转指定步数 }, gohome() { //push的两种写法 // this.$router.push('/first').then(() => console.log('完成跳转')).catch(() => console.log('跳转失败')); //如果是replace的话,那么就不会生成记录 this.$router.push({name: 'aaa'}, ()=> console.log('ok'), ()=> console.log('no')); } }, router: new VueRouter({mode: 'hash', routes}) }); </script> </body>
11、如何配置页面刷新
配置redirect的路由
{ path: '/redirect', component: Layout, //如有外层框架 hidden: true, children: [ { path: '/redirect/:path*', component: () => import('@/views/redirect/index') } ] }
redirect组件内容
<script> export default { created () { const { params, query } = this.$route const { path } = params this.$router.replace({ path: '/' + path, query }) }, render: h => h() //阻止警示信息 } </script>
跳转:
this.$router.replace({ path: '/redirect' + fullPath })
注意:在router-view外围需要配置keep-alive如下
<transition name="fade-transform" mode="out-in"> <keep-alive :include="cachedViews"> <router-view :key="key"></router-view> </keep-alive> </transition>
注意: keep-alive中有两个参数,include: 字符串或正则表达式。只有匹配的组件会被缓存。exclude: 字符串或正则表达式。任何匹配的组件都不会被缓存。
exclude优先级大于include,例子中的cachedViews的类型是Array<string>
<keep-alive include="test-keep-alive"> <!-- 将缓存name为test-keep-alive的组件 --> <component></component> </keep-alive> <keep-alive include="a,b"> <!-- 将缓存name为a或者b的组件,结合动态组件使用 --> <component :is="view"></component> </keep-alive> <!-- 使用正则表达式,需使用v-bind --> <keep-alive :include="/a|b/"> <component :is="view"></component> </keep-alive> <!-- 动态判断 --> <keep-alive :include="includedComponents"> <router-view></router-view> </keep-alive> <keep-alive exclude="test-keep-alive"> <!-- 将不缓存name为test-keep-alive的组件 --> <component></component> </keep-alive>
include
和 exclude
属性允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示:匹配首先检查组件自身的 name
选项,如果 name
选项不可用,则匹配它的局部注册名称 (父组件 components
选项的键值)。匿名组件不能被匹配。
也就相当于先匹配components里的name名字,所以取名的时候尽量与与过滤的一致
重点:在hash环境下,刷新页面显示404,这个时候面beforeEach的时候更改为next({...to, replace: true})便可