ue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-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="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 路由导航 router-link-->
<router-link to="/foo" tag="button">Go to Foo</router-link>
<router-link to="/bar" tag="button">Go to Bar</router-link>
</p>
<!-- 路由视图 router-view-->
<router-view></router-view>
</div>
<script>
//根据路由匹配规则创建一个路由器
const router = new VueRouter({
//定义路由匹配规则
routes: [
//其中"component" 可以是通过 Vue.extend() 创建的组件构造器,或者,只是一个组件配置对象。
{ path: '/foo', component: { template: 'foo' } },
{ path: '/bar', component: { template: 'bar' } }
]
});
//让这个实例使用此路由器
new Vue({
el: "#app",
router: router,
})
</script>
</body>
</html>
以下两种实现方式得到的效果一样
当对应的路由匹配成功,将自动设置类
我们可以给这个类设置些默认的样式,达到让他实现选中的效果
效果图:
可以修改这两个默认的类名,用自己喜欢的类名来定义
效果图:
命名代码:
linkActiveClass: 'active',
linkExactActiveClass: 'active',
可以直接在router上设置行内样式或者class,是可以生效的,会自动注入到生成的网页标签上
<router-link style="color:red;font-size: 50px;" to="/foo">Go to Foo</router-link>
显示路由器中定义的组件
<!-- 路由视图 router-view-->
<router-view></router-view>
首先要定义route, 一条路由的实现。它是一个对象,由两个部分组成: path和component. path 指路径,component 指的是组件
我们这里有两条路由,组成一个routes:
routes: [
//其中"component" 可以是通过 Vue.extend() 创建的组件构造器,或者,只是一个组件配置对象。
{ path: '/foo', component: { template: 'foo' } },
{ path: '/bar', component: { template: 'bar' } }
]
创建router 对路由进行管理,它是由构造函数 new vueRouter() 创建,接受routes 参数
const router = new VueRouter({
routes // routes: routes 的简写
})
配置完成后,把router 实例注入到 vue 根实例中,就可以使用路由了
new Vue({
el: "#app",
router: router,
})
完整代码:
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 路由导航 router-link-->
<router-link to="/foo" tag="button">Go to Foo</router-link>
<router-link to="/bar" tag="button">Go to Bar</router-link>
</p>
<!-- 路由视图 router-view-->
<router-view></router-view>
</div>
<script>
//定义路由匹配规则
var routes = [
//其中"component" 可以是通过 Vue.extend() 创建的组件构造器,或者,只是一个组件配置对象。
{ path: '/foo', component: { template: 'foo' } },
{ path: '/bar', component: { template: 'bar' } }
]
//根据路由匹配规则创建一个路由器
const router = new VueRouter({
routes
});
//让这个实例使用此路由器
new Vue({
el: "#app",
router: router,
});
</script>
单个路由"component" 的值可以只是一个组件配置对象也就是说可以通过 Vue.extend() 创建的组件构造器,如下:
效果图:
你可以在一个路由中设置多段“路径参数”,对应的值都会设置到 $route.params 中
效果图:
当使用动态路径参数发生变化时,从例如/link:1导航到/link:2,原来的组件实例会被复用
因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用
如下面的钩子函数只调用了一次,即复用了组件。如果是通过路由从其他组件过来的话,那么组件是会重新再次创建的
效果图:
可以看到mounted中的语句只执行了一次
路径参数变化时才会触发beforeRouteUpdate
匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高
由于组件渲染的地方由对应路由的层级决定,所以只要我们在被嵌套的路由组件中的routr-link标签的to属性赋值为上层路由的路径,那么根视图就会渲染对应组件,从而实现常见业务:从子内容中跳转到主内容中去
//不管是决定路径还是相对路径都可以实现
<router-link to="/bar">foo_1</router-link>
<router-link to="../bar">foo_2</router-link>
前面我们通过
我们还可以如同操作window.history一样进行编程式的操作路由(通过js编程)
Vue中的编程式路由是模仿window.history而实现的,所以其提供的api和window.history提供的api非常相似
实际上当你点击 时,router.push这个方法也会在内部调用,所以说,点击
这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL
效果图:
this.$router.push({path:"/foo"});
this.$router.push({ path: "/foo", query: { sex: "man", age: 18 } });
//等价于 /foo:123,会匹配规则为/foo:id的规则
this.$router.push({ path: "/foo:123"});
用户在提交一则信息,跳转到下一个页面后,如果点了返回按钮,用户就会返回到信息填写的页面,这对于像订单支付页面这种界面并不友好
这时我们就可以使用 replace方法替换掉push,replace方法会直接替换掉当前的 history 记录
methods: {
toFoo:function(){
this.$router.replace(
{path:'/foo'},
)
}
}
如果使用router-link标签,直接在上面添加replace属性即可
<router-link :to="foo" replace>Go to foo</router-link>
在 2.2.0+,可选的在 router.push 中提供 onComplete 和 onAbort 回调作为第二个和第三个参数
这些回调将会在导航成功完成 (在所有的异步钩子被解析之后) 或终止 (导航到相同的路由、或在当前导航完成之前导航到另一个不同的路由) 的时候进行相应的调用
对位传参
methods: {
toFoo: function () {
this.$router.replace({ path: "/foo"},
function (to) {
console.log("跳转成功", to);
}, function (to) { //跳转失败时的目标路由 to 为undefined
console.log("跳转失败", to);
});
}
}
注意:如果目的地和当前路由相同,只有参数发生了改变 (比如从一个用户资料到另一个 /users:1 -> /users:2),也会触发跳转成功的回调函数
这个方法的参数是一个整数,意思是在 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 实例的时候,在 routes 配置中给某个路由设置名称
使用编程式路由:
//路由配置
const router = new VueRouter({
routes: [
{
path: '/bar',
component: Bar,
name: "mybar",
}
]
});
//调用
this.$router.push({ name: 'mybar' });
声明式路由
const router = new VueRouter({
routes: [
{
path: '/bar',
component: Bar,
name: "mybar",
}
]
});
//调用
<router-link :to="bar" tag="button" replace>路由导航2</router-link>
new Vue({
el: "#app",
router: router,
data:{
bar:{name:"mybar"}
},
});
当同级同时刻显示多个视图时,我们就可以使用命名视图了,我们可以在界面中拥有多个单独命名的视图,而不是只有一个单独的视图
如果 router-view 没有设置名字,那么默认为名字为 default
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/foo" tag="button">路由导航1</router-link>
<router-link to="/bar" tag="button">路由导航2</router-link>
</p>
<router-view style="border:1px solid black"></router-view>
<router-view name="one" style="border:1px solid red"></router-view>
<router-view name="two" style="border:1px solid green"></router-view>
</div>
<script>
let Foo_1 = Vue.extend({
template: `我是组件Foo1
`,
});
let Foo_2 = Vue.extend({
template: `我是组件Foo2
`,
});
let Foo_3 = Vue.extend({
template: `我是组件Foo3
`,
});
let Bar_1 = Vue.extend({
template: `我是组件Bar1
`,
});
let Bar_2 = Vue.extend({
template: `我是组件Bar2
`,
});
let Bar_3 = Vue.extend({
template: `我是组件Bar3
`,
});
const router = new VueRouter({
routes: [
{
path: '/foo', components: {
default: Foo_1,
one: Foo_2,
two: Foo_3,
},
},
{
path: '/bar', components: {
default: Bar_1,
one: Bar_2,
two: Bar_3,
}
},
]
});
new Vue({
el: "#app",
router: router,
});
</script>
将路由规则中component选项修改为redirect,其值为一个路由的地址如:/foo
重定向结果:当跳转到路由为/test时会渲染/foo所在组件
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/foo" tag="button">路由导航1</router-link>
<router-link to="/bar" tag="button">路由导航2</router-link>
<router-link to="/test" tag="button">重定向</router-link>
</p>
<router-view style="border:1px solid black"></router-view>
</div>
<script>
let Foo = Vue.extend({
template: `我是组件Foo
`,
});
let Bar = Vue.extend({
template: `我是组件Bar
`,
});
const router = new VueRouter({
routes: [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar },
{ path: '/test', redirect: '/foo' }
]
});
new Vue({
el: "#app",
router: router,
});
</script>
/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样
<router-link to="/test" tag="button">路由导航2</router-link>
const router = new VueRouter({
routes: [
{ path: '/bar', component: Bar, alias:'/test' },
]
});
当我们通过路由规则跳转到不同的组件上时,我们可以在路由规则定义中传入参数
我们可以在路由规则对象上添加一个props属性,其值设置为true,如果 props 被设置为 true,route.params (动态路径参数,也就是冒号后面的东西) 将会被设置为组件属性
路由规则中冒号后面的路径参数会作为参数名,发起路由请求时传来的值就是其参数值。然后在组件中必须使用props来接收才能使用这个参数
效果图:
这里Foo组件规则中的props设置为false,所以接收不到参数
可以创建一个函数返回 props。这样能够把静态值与基于路由的值结合作为参数传递给对应组件
效果图:
对前端而言,要将hash模式修改为history模式,只需要添加mode属性即可
友情提示:
对于history模式,需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器刷新时就会直接404了(使用history模式时不怕前进也不怕后退,就怕刷新…)所以呢,服务端需要增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面
当我们通过路由来切换组件时,网页的标题不会改变
但其实我们是希望他改变的,或者有这种需求,这时候我们就可以使用路由钩子函数BeforeEach方法,他会在路由改变前触发
Next方法可以设置参数
当我们参数为false时,就可以取消导航
当我们设置为具体的路径时可以导航到指定页面
afterEach方法在路由改变后触发,一些较为实用的例子为: