Vue Router(路由)--总结
(一)路由基础
1.概念
vue.js中路由相当于就是局部刷新,根据不同的url地址展现不同的内容或者页面,是vue.js中的核心组件,由vue.js官方维护的路由管理器。通过路由可以构建用户体验较高的单页应用程序。
2.路由的定义以及使用
① 引入必要的脚本文件Vue.js和Vue-Router.js,在引入脚本文件时,一定要注意引入的顺序,应当先引入Vue.js文件然后引入Vue-Router.js文件。
Vue.js文件下载地址:https://www.bootcdn.cn/vue/
Vue-Router.js文件下载地址:https://www.bootcdn.cn/vue-router/
② 路由的定义。在定义路由时分为两个部分,一部分是html文件中编写的html代码,一部分是JavaScript中编写的js代码。
html代码:
<div id="app">
<h1>路由的定义</h1>
<div>
<router-link to="/stu">学生</router-link>
<router-link to="/tea">老师</router-link>
</div>
<div>
<router-view></router-view>
</div>
</div>
js代码:
//创建学生组件
var stu={
template:`<div>学生界面</div>`
}
//创建老师组件
var tea={
template:`<div>这是一个老师界面</div>`
}
//创建路由对象
var routers=[{path:"/stu",component:stu},{path:"/tea",component:tea}]
//实例路由器
var router=new VueRouter({routes:routers});
var vm=new Vue({
el:"#app",
router:router,
})
在html文件中主要是定义模板,通过不同的url地址将不同的内容渲染到页面上。
js文件中所包含有,先创建路由组件,创建路由对象,实例化路由,挂载根实例,路由是通过HTML上router-link中to上的ulr地址在路由对象中找到对应的组件渲染到页面上。路由就是将不同组件通过绑定一个地址,最后通过地址来渲染到页面上。
(二)动态路由
① 动态路由:路由的信息不是固定的,是可以动态改变的。动态路由是能出传递参数的路由模式,由于可以传递参数,所以其对应的路由数量是不确定的。动态路由传递的参数是通过将参数卸载路由的path上并在参数名前面加上 ' : '。代码实现如下:
<--html代码-->
<div id="app">
<h3>动态路由</h3>
<div>
<router-link to="/user/stu/100">学生</router-link>
<router-link to="/user/tea/10">老师</router-link>
</div>
<div>
<router-view></router-view>
</div>
</div>
<--js代码-->
<script>
//创建组件
var user={
template:`<div>我是一个{{$route.params["name"]=="stu"?"学生":"老师"}} id={{id}}</div>`,
props:["id"]
}
//定义路由
var routes=[{path:"/user/:name/:id",component:user,props:true}]
//实例路由
var router=new VueRouter({routes})
var vn=new Vue({
el:"#app",
router,
})
</script>通过在定义路由是设置动态路由的参数,在组件上也可以通过路由的参数来渲染不同信息。通过html上配置的路由跳转使用标签router-link上传递过来的参数值来跳转不同的组件信息。
② 路由之间传递参数
1.路由之间传递参数params方式
在路由跳转(定义路由数组)的时候定义要传递的参数
var routes=[{path:"/user/:name/:id",component:user,props:true}]页面跳转的时候传递参数信息
<router-link to="/user/stu/100">学生</router-link>在组件中接受传递过来的参数
template:`<div>我是一个{{$route.params["name"]=="stu"?"学生":"老师"}} id={{id}}</div>`2.路由之间传递参数query方式
在路由跳转的地方传递query参数
<router-link v-bind:to="{path:'/user/stu',query:{id:123}}">路由2</router-link>
在组件中接受传递过来的参数
template: `<div>id={{this.$route.query.id}}</div>`
(三)嵌套路由
① 嵌套路由:就是在路由中还包含有另外的路由,就是路由的多层嵌套。
② 定义嵌套路由的要求:嵌套路由是通过children数组来定义子路由的,将children数组放在父级路由的定义中。并且子路由的路径path属性上不用加 “ / ”,因为以“ / ”开头的嵌套路径会被当作根路径。在生成路由时,主路由上的path会被自动添加到子路由前,所以子路由上的path不用在重新声明主路由上的path。
实现图:

嵌套路由的代码如下:
<--html代码-->
<div id="app">
<button @click="fa1">父级1</button><button @click="fa2">父级2</button>
<router-view></router-view>
</div>
<--js代码-->
<script>
var childrens1 = {
template: `
<div>
<h1>路由孩子1</h1>
</div>
`
}
var childrens2 = {
template: `
<div>
<h2>路由孩子2</h2>
</div>
`
}
var childrens3 = {
template: `
<div>
<h3>孩子3</h3>
</div>
`
}
var childrens4 = {
template: `
<div>
<h4>孩子4</h4>
</div>
`
}
var component1 = {
template: `
<div>
<h4>我是主路由1</h4>
<button @click="chil1">路由孩子1</button><button @click="chil2">路由孩子2</button>
<router-view></router-view>
</div>
`,
methods: {
chil1() {
router.push({
path: "/father1/child1"
})
},
chil2() {
router.push({
path: "/father1/child2"
})
},
}
}
var component2 = {
template: `
<div>
<h3>我是主路由2</h3>
<button @click="chil3">孩子1</button><button @click="chil4">孩子2</button>
<router-view></router-view>
</div>
`,
methods: {
chil3() {
router.push({
path: "/father2/child3"
})
},
chil4() {
router.push({
path: "/father2/child4"
})
},
}
}
var routes = [{
path: "/father1",
component: component1,
children: [{
path: "child1",
component: childrens1,
}, {
path: "child2",
component: childrens2,
}]
}, {
path: "/father2",
component: component2,
children: [{
path: "child3",
component: childrens3
}, {
path: "child4",
component: childrens4
}]
}]
var router = new VueRouter({
routes: routes
})
var vm = new Vue({
el: "#app",
router: router,
methods: {
fa1() {
router.push({
path: "/father1"
})
},
fa2() {
router.push({
path: "/father2"
})
},
}
})
</script>
其实嵌套路由的写法和写动态路由差不多,只不过在一个路由中嵌套路由的时候,子路由的定义要用children定义在父路由器的定义中,而子路由器的调用方法和参数的传递都要写在相关的父路由器的组件中。而父路由的定义还是和动态路由一样的。嵌套路由的原理也是通过path地址的查找来渲染相对应的组件。
(四)编程式导航的方法
除了使用<router-link>创建a标签来定义导航,我们还可以借助router的实例方法,通过编写代码来实现。
① router.push()
这个方法会向history(历史记录)栈添加一个新的记录,所以当用户点击浏览器的后台按钮时,则会返回到之前的URL。
点击<router-link to="...">时等于调用router.push(...).
语法:router.push(location,onComplete?,onAbort?)
location:导航的地址信息。
onComplete:导航成功完成时调用的回调函数(少用)
onAbort:导航终止后的回调函数(少用)
location参数又可以分为四种:
1.字符串 router.push("/stu")
2.对象 router.push({path:“/stu”})
3.命名路由 router.push({name:"政委",params:{name:"stu",id:100})
4.带查询参数 router.push({path:"/user/stu/100",query:{ids:88}})
详细代码如下:
字符串和对象:
<div id="app">
<h3>编程式导航</h3>
<button @click="sturou">学生</button>
<button @click="tearou">老师</button>
<router-view></router-view>
</div>
<script>
// //创建学生组件
var stu = {
template: `<div>学生界面</div>`
}
// //创建老师组件
var tea = {
template: `<div>这是一个老师界面</div>`
}
//创建路由对象
var routers = [{
path: "/stu",
component: stu,
name: "政委"
}, {
path: "/tea",
component: tea,
name: "首长"
}]
//实例路由器
var router = new VueRouter({
routes: routers
});
var vm = new Vue({
el: "#app",
router: router,
methods: {
sturou() {
//用字符串查找路径
// router.push("/stu")
//用对象查找路径,根据对象中属性查找路由对象中对应的属性
router.push({
path: "/stu"
})
},
tearou() {
//router.push("/tea")
router.push({
path: "/tea"
})
}
}
})
命名路由与带can查询:
<div id="app">
<h3>编程式导航</h3>
<button @click="sturou">学生</button>
<button @click="tearou">老师</button>
<router-view></router-view>
</div>
<script>
var user = {
template: `<div>我是一个{{$route.params["name"]=="stu"?"学生":"老师"}} id={{id}} ids={{$route.query.ids}}</div>`,
props: ["id"]
}
var routers = [{
path: "/user/:name/:id",
component: user,
name: "政委",
props: true
}]
//实例路由器
var router = new VueRouter({
routes: routers
});
var vm = new Vue({
el: "#app",
router: router,
methods: {
sturou() {
//命名的路由
// router.push({name:"政委",params:{name:"stu",id:100}})
//带查询参数
router.push({
path: "/user/stu/100",
query: {
ids: 88
}
})
},
tearou() {
// router.push({name:"政委",params:{name:"tea",id:10}})
router.push({
path: "/user/tea/10",
query: {
ids: 99
}
})
}
}
})
</script>
其实命名路由和带查询参数路由也是通过对象的形式,只不过对象中的属性不同,命名路由查询的方式是通过查找路由的name值,它的参数是通过params属性来传递,他在父级是通过params来接收参数的。而带查询参数是通过路径path来查找路由,通过query属性来传递参数,在父级是通过query接收参数的来。而这两两的搭配是固定的是不能交换的。
② router.replace()
这个方法和router.push()很像,唯一的不同就是,它不会向history(历史记录)添加新记录,而是跟他的方法名一样——替换掉当前的history记录。
语法:router.replace(location,onComplete?,onAbort?)
和上面的用法是一样的这里就不举例了!这里来说说这两个方法后面的两个参数。
onComplete导航成功完成时调用的回调函数,onAbort导航终止后的回调函数,这两个都是回调函数,只是调用的时间不同,回调函数中你要使用什么东西可以根据自己的需求来书写。
代码:
methods: {
sturou() {
router.push({
path: "/stu"
}, onComplete, onAbort)
},
tearou() {
router.push({
path: "/tea"
}, onComplete, onAbort)
},
onComplete() {
console.log("导航完成前")
},
onAbort() {
console.log("导航完成后")
}
}
视图:

③ router.go(n)
这个方法的参数是一个整数,意思是在history(历史记录)记录中向前或者后退多少步,类似window.history.go(n)。
// 在浏览器记录中前进一步,等同于 history.forward()
router.go(1)
// 后退一步记录,等同于 history.back()
router.go(-1)
// 前进 3 步记录
router.go(3)
// 如果 history 记录不够用,那就默默地失败呗
router.go(-100)
router.go(100)
(五)命名视图
有时候想同时(同级)展示多个视图,而不是嵌套展示,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default。
<div id="app">
<h3>编程式导航</h3>
<router-link to="/stu">命名视图</router-link>
<router-view></router-view>
<router-view name="a"></router-view>
<router-view name="b"></router-view>
</div>
<script>
// //创建学生组件
var stu = {
template: `<div>学生界面</div>`
}
// //创建老师组件
var tea = {
template: `<div>这是一个老师界面</div>`
}
//创建默认组件
var def = {
template: `<div>这是一个默认界面</div>`
}
//创建路由对象
var routers = [{
path: "/stu",
components: {
a: stu,
b: tea,
default: def
}
}]
//实例路由器
var router = new VueRouter({
routes: routers
});
var vm = new Vue({
el: "#app",
router: router,
})
</script>
实现图:

命名视图要展示多个视图,就只要定义一个路由对象,在路由对象中的实例组件时,用不同的名字。用来与<router-view>中的name来匹配。
(六)重定向
重定向(redirect)就是通过各种方法将各种网路请求重新定个方向转到其他位置。用于网站调整或网页被移到一个新地址,它也是通过routes配置来完成。
<div id="app">
<h1>重定向</h1>
<div>
<router-link to="/stu">学生</router-link>
</div>
<div>
<router-view></router-view>
</div>
</div>
</body>
<script>
//创建学生组件
var stu = {
template: `<div>学生界面</div>`
}
//创建老师组件
var tea = {
template: `<div>这是一个老师界面</div>`
}
//创建路由对象
var routers = [{
path: "/stu",
redirect: "/tea",
component: stu
}, {
path: "/tea",
component: tea
}]
//实例路由器
var router = new VueRouter({
routes: routers
});
var vm = new Vue({
el: "#app",
router: router,
})
</script>
在上面的代码中的
{
path: "/stu",
redirect: "/tea",
component: stu
}要展现视图“/stu”的时候会直接跳转到“/tea”上,不会去渲染stu上的内容而是会直接渲染tea上的内容。
(七)别名
如“/a”的别名是"/b",意味着,当用户访问/b时,URL会保持为/b,但是路由匹配则会为/a,就像用户访问/a一样。简单的说就是给/a起一个外号叫做/b,但是本质上还是/a。
<div id="app">
<h1>路由的定义</h1>
<div>
<router-link to="/stu">学生</router-link>
<router-link to="/tea">老师</router-link>
</div>
<div>
<router-view></router-view>
</div>
</div>
<script>
//创建学生组件
var stu = {
template: `<div>学生界面</div>`
}
//创建老师组件
var tea = {
template: `<div>这是一个老师界面</div>`
}
//创建路由对象
var routers = [{
path: "/stu",
component: stu,
alias: "/tea"
}]
//实例路由器
var router = new VueRouter({
routes: routers
});
var vm = new Vue({
el: "#app",
router: router,
})
</script>
不管是点“老师“还是“学生“都是“学生界面”,相当于“学生”的这个路由有两个路由地址。
(八)导航守卫
正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。
① 全局监听事件
全局监听事件包括有前置守卫和后置守卫。
全局前置守卫:router.beforeEach(to,from,next)
to: Route: 即将要进入的目标 路由对象
from: Route: 当前导航正要离开的路由
next:是一个回调函数,一定要调用该方法来调用钩子函数,执行的效果依赖next方法的调用参数。
参数对比:
为空时:执行当前导航
false:中断当前导航。
“/”或{path:“/”}:当前的导航中断,跳转到一个不同的地址。
error:导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
<div id="app">
<button @click="teas">老师</button>
<button @click="stus">学生</button>
<router-view></router-view>
</div>
<script>
var zujian = {
template: `
<div>我是{{$route.params["name"]=="stu"?"学生":"老师"}},id={{id}} ids={{$route.query.ids}}</div>
`,
props: ["id"]
}
var routes = [{
path: "/user/:name/:id",
component: zujian,
props: true
}]
var router = new VueRouter({
routes: routes
})
router.beforeEach((to, from, next) => { //全局前置守卫 在路由渲染前调用的钩子函数
console.log("前");
next(); //在这里进行判断是否渲染 如果渲染则调用next(),不渲染则不调用
})
var vm = new Vue({
el: "#app",
router,
methods: {
teas() {
router.push({
path: "/user/tea/100",
query: {
ids: "stu"
}
})
},
stus() {
router.push({
path: "/user/stu/80",
query: {
ids: "tea"
}
})
}
}
})
</script>
视图:


点击切换路由的时候就会先调用全局前置守卫事件。
全局后置守卫:router.afterEach(to,from,next)用法和前置守卫一样,只是事件发生的时间不同,它事件发生的时间是在路由渲染以后才会调用。
② 路由独享的守卫
beforeEnter(to,from,next),用法和全局守卫是一样的,只是它只有在调用它定义的那一个路由时才会触发事件。
③ 组件内的守卫
beforeRouteEnter(to, from, next) {
// 在渲染该组件的ù应路由被 confirm 前调用
// 不!能!获取组件例 `this`
// 因为当卫执行前,组件例还没被创建
// 不过可以通过回调函数来获取,代码如下:
next(vm => {
// 通过 `vm` 访问组件实例
})
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}