Vue Router 是Vue.js的官方路由器。
学习Vue Router之前,先了解路由中的三个基本的概念 route
, routes
, router
。
1、 route
,它是一条路由,由这个英文单词也可以看出来,它是单数, Home按钮 => home内容, 这是一条route, about按钮 => about 内容, 这是另一条路由。
2、 routes
是一组路由,把上面的每一条路由组合起来,形成一个数组。[{home 按钮 =>home内容 }, { about按钮 => about 内容}]
3、 router
是一个机制,相当于一个管理者,它来管理路由。因为routes 只是定义了一组路由,它放在哪里是静止的,当真正来了请求,怎么办? 就是当用户点击home 按钮的时候,怎么办?这时router 就起作用了,它到routes 中去查找,去找到对应的 home 内容,所以页面中就显示了 home 内容。
4、客户端中的路由,实际上就是dom 元素的显示和隐藏。当页面中显示home 内容的时候,about 中的内容全部隐藏,反之也是一样。客户端路由有两种实现方式:基于hash
和基于html5 history
api。(一般使用history)
一、使用 vue-router
1、安装vue-router
cnpm install --save-dev vue-router
2、src目录下新建一个router.js 文件定义router, 就是定义 路径到 组件的 映射。
引入vue-router,并关联vue-router到vue:
import Vue from "vue";
import vueRouter from "vue-router";
Vue.use(vueRouter);
引入组件:
import Home from './components/Home'
import Regest from './components/Regset'
import Login from './components/Login'
import Send from './components/Sendmsg'
import Sendget from './components/Sendget'
配置路由节点
const routes=[
{
path: "/",
component: Home,
name: "homeinfo",
//局部守卫
beforeEnter: (to, from, next) => {
console.log(to, from);
next();
}
},
{ path: "/regest", component: Regest, name: "regestinfo" },
{
path: "/login/:id",
component: Login,
name: "logininfo",
alias: "/userlogin", //alias 属性为命名别名
//路由嵌套
children: [
{
path: "user",
component: User
}
]
},
//用户输入的地址不存在 默认指向那个路径
{ path: "*", redirect: "/" },
{ path: "/user", redirect: "/login" },
//根据name属性重定向
{ path: "/list", redirect: { name: "logininfo" } },
//配置路由的动态传参
{ path: "/sendMsg/:id/:name", component: Send, name: "send" },
{ path: "/Sendget", component: Sendget, name: "sendget" }
];
const router = new vueRouter({
routes,
mode: "history" //修改路由路径的模式 默认hsl模式 #/ history 正常的路径
});
暴露出 router:
export default router;
3、在main.js里边引入路由模块,并注入到vue根实例中
引入路由模块:
import router from "./router.js"
// import router 的router 一定要小写, 不要写成Router, 否则报 can't match的报错
注入到根实例:
new Vue({
el: '#app',
router,
render: h => h(App)
})
4、app模板内部写路由的入口 <router-link >
和出口 </router-view>
(1)路由入口:
<router-link>
定义点击后导航到哪个路径下,默认会被渲染成一个<a>
标签;
<router-link to="/regest"> regest </router-link>
(2)路由出口:
对应的组件内容渲染到<router-view>
中;
<router-view></router-view>
(3)路由入口路径的动态绑定:
HTML代码:
<router-link v-for="(item,index) in menu" :key="index" :to="item.action">{{item.name}}</router-link>
JavaScript代码:
data() {
return {
menu: [
{ name: "home", action: "/" },
{ name: "regest", action: "/regest" },
{ name: "login", action: "/login/10086" },
],
};
},
二、路由的重定向 redirect
和别名 alias
1、重定向
重定向是指用户访问时/a
,URL将被替换/b
,然后与匹配/b
。
重定向也在routes
配置中完成,使用redirect
属性。
(1)用户输入的地址不存在,默认指向某个路径:
{ path: "*", redirect: "/" }
(2)用户输入地址,重定向到其它地址:
{ path: "/user", redirect: "/login" }
(3)根据name属性重定向:
{ path: "/list", redirect: { name: "logininfo" } }
2、别名
给/a
设置别名为 /b
:表示用户访问/b
时,URL保持/b
不变,但将被匹配/a
路由。
别名也在routes
配置中完成,使用alias
属性。
{
path: "/login",
component: Login,
name: "logininfo",
alias: "/userlogin",
}
三、路由的传参
1、路由动态传参
在配置routes
时,直接在path
属性上配置参数。
一旦设置为动态路由传参,调用路由时就必须传递参数,否则访问不到。
routes
里边配置参数:
{ path: "/sendMsg/:id/:name", component: Send, name: "send" }
组件里边获取值:在this.$route
对象上获取(this.$route.params
)。
this.$router
获取的路由对象,可以实现路由跳转。
mounted(){
//组件挂在完成之后去获取路由的动态传参
console.log(this.$route.params);
},
2、路由get传值
路由get传值,是直接在路径上写传值,类似原生js里边的get传值。不需要在routes
的path
属性上配置。
获取路由的get传值:this.$route.query
mounted(){
//获取路由的get传值
console.log(this.$route.query);
},
3、在路由入口<router-link>
上进行路由传值绑定
<!-- 路由动态传值、get传值绑定 -->
<router-link :to="`/sendMsg/${id}/${name}`">sendMsg</router-link>
<router-link :to="`/Sendget?id=${id}&name=${name}`">sendMsg</router-link>
<!-- get路由传值 还可以写成下面这个格式 -->
<router-link :to="{path:'/Sendget',query:{id:id,name:name}}">sendget</router-link>
4、对参数变化做出反应
使用带参数的路由时要注意的一件事是,当用户从导航/user/foo
到/user/bar
时,将重用相同的组件实例。由于两个路由都呈现相同的组件,因此这比销毁旧实例然后创建新实例更有效。但是,这也意味着将不会调用组件的生命周期钩子。
要对同一组件中的参数更改做出反应,只需观察$route对象即可:
watch:{
$route(from,to){
if(to.name==from.name)
{
console.log("同一个路由不同参数",from,to);
//这里可以根据参数变化手动更新相关数据
}
}
}
或者,使用2.2中引入的beforeRouteUpdate
导航卫士:
const User = {
template: '...',
beforeRouteUpdate (to, from, next) {
// react to route changes...
// don't forget to call next()
}
}
四、路由的嵌套
真正的应用程序用户界面通常由嵌套在多个级别的组件组成。App主模板的<router-view>
是路由的顶级出口,它使组件与顶层路线匹配,同样,App
模板中渲染的组件也可以包含自己的 <router-view>
,即:子路由。(注意:只有根路径在routes
里边配置的时候,path
属性值才需要加“/
”)
routes: [
{
path: '/user/:id', component: User,
children: [
// UserHome will be rendered inside User's <router-view>
// when /user/:id is matched
{ path: 'userhome', component: UserHome },
// ...other sub routes
]
}
]
如果要将二级路由设为默认路由(进入一级路由后直接加载该二级路由),将二级路由的
path
属性值设为空即可path:" "
。
五、编程式导航
除了上边提到的<router-link>
,通过点击实现路由跳转;也可以通过事件、逻辑代码实现路由跳转,这就是编程式导航。
编程式导航不能跨级跳转。只能同级或上一级、下一级。
1、this.$router.push()
在Vue实例内部,可以访问到路由器实例$router
。因此,可以通过this.$router.push()
方法航到其他URL。
此方法将新条目推入历史记录堆栈,因此,当用户单击浏览器后退按钮时,它们将被带到先前的URL。
this.$router.push()
的参数:
参数可以是字符串路径,也可以是位置描述符对象。
// literal string path
router.push('home')
// object
router.push({ path: 'home' })
// named route
router.push({ name: 'user', params: { userId: '123' } })
// with query, resulting in /register?plan=private
router.push({ path: 'register', query: { plan: 'private' } })
2、this.$router.replace()
就像router.push
一样,唯一的区别是它导航时没有推送新的历史记录条目,顾名思义-它替换了当前条目。
3、this.$router.go(n)
此方法采用单个整数作为参数,该参数指示在历史记录堆栈中前进或后退多少步,类似于window.history.go(n)
。
以上几种方法的使用:
<template>
<div id="user">
user
<button @click="goroute">点击进入**页面</button>
<button @click="goback">点击回退</button>
</div>
</template>
<script>
export default {
name:"user",
methods:{
goroute(){
//this.$router.push("/login/10086");
this.$router.replace("/login/10086");
},
goback(){
this.$router.go(-1);
}
}
}
</script>
六、路由的安全守卫
主要用于通过重定向或取消导航来保护导航。有很多方法可以挂接到路线导航过程中:全局,每个路线或组件内。
1、全局守卫
(1)路由执行之前: router.beforeEach()
在路由触发之前可以做一些状态处理。
每当触发导航时,将按创建顺序调用全局警戒。可以异步解决保护措施,并且在解决所有挂钩之前将导航视为挂起状态。
router.beforeEach((to, from, next) => {
console.log(to, from);
if (to.name != "sendget") {
next("/Sendget"); //next({padth:"/home"})
}
else {
next();
}
});
to
:Route: 要导航到的目标对象;
from
: Route:正在远离的当前路线;
next()
进行管道中的下一个,不写next()
,路由终止;
next(false)
终止当前路由;
next("/")
,next({padth:"/"})
参数为路径时,重定向路由。
注意:
确保
next
在通过导航防护装置的任何给定遍历中,仅一次调用该函数。它可以出现多次,但前提是逻辑路径没有重叠,否则钩子将永远无法解决或产生错误。
(2)路由执行之后: router.afterEach()
注意:该钩子没有next
功能,因此不会影响导航。
router.afterEach((to, from) => {
console.log(to, from);
});
2、局部守卫:beforeEnter
可以beforeEnter
直接在路由的配置对象上定义防护:(针对某个路由的私有守卫)
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
3、组件内防护
直接在组件内部写安全守卫:
beforeRouteEnter(to,from,next){}
beforeRouteUpdate(to,from,next){}
beforeRouteLeave(to,from,next){}
<script>
export default {
name: "login",
methods: {
//......
},
// 组件内部的路由安全守卫
beforeRouteEnter(to, from, next) {
console.log("进入之前");
//路由进入之前 当前组件没有实例化
next((vm) => {
console.log(vm); //vm 形参代表组件的实例
});
},
beforeRouteUpdate(to, from, next) {
//当前路由不变 参数发生变化 时触发
console.log(this);
next();
},
beforeRouteLeave(to, from, next) {
console.log("离开之前");
console.log(this);
next();
},
};
</script>
beforeRouteEnter
里边访问不到this
,因为此时组件还没有实例化。
注意:
beforeRouteEnter
是唯一支持将回调传递给next
的防护措施。对于beforeRouteUpdate
和beforeRouteLeave
,this
已经可用,因此不需要传递回调,因此不支持。
七、给路由添加过渡
可以用 <transition></transition>
包裹路由出口<router-view></router-view>
来为路由添加过渡(相当于给路由对应的组件添加过渡),<transition>
用法同vue自定义动画,也可以使用animate.css
。
html:
<transition name="fade" duration="200" mode="out-in">
<router-view></router-view>
</transition>
css:
<style>
.fade-leave-active {
transition: transform 0.2s ease-in;
}
.fade-leave-to {
transform: translatex(-100%);
}
.fade-enter-active {
transition: transform 0.2s ease-in;
}
.fade-enter {
transform: translatex(100%);
}
</style>
八、路由延迟加载
就是将路由里边配置的组件写成异步加载。
参考另一篇博客(vue组件)里边的“异步组件”。