下载
- 依赖:
npm install vue-router --save
- 导入路由对象,并且调用
Vue.use(VueRouter)
- 创建路由实例,并且传入路由映射配置
- 在
Vue实例中,挂载创建的路由实例
- 使用路由 和
配置基本的路由并使用
- 新建
router文件内置index.js文件import Vue from 'vue';
import VueRouter from 'vue-router';//引入插件
Vue.use(VueRouter);//通过Vue.use(插件),安装插件
import home from '@pages/home/home.vue';
import about from '@pages/about/about.vue';
const routes=[//配置路径和组件之间的映射关系
{path:'/home',component:home},
{path:'/about',component:about}
]
const router =new VueRouter({//创建VueRouter对象
routes:routes
});
export{//导出router
router
}
/**
* 使用vue-router的三个步骤
* 创建路由组件
* 配置路径和组件之间的映射关系
* 使用路由 <router-link>和<router-view>
*/
main.js中引入导出的router,并挂载到vue实例上import {router} from './router/index'
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
App.vue中<template>
<div id="app">
<router-link to='/home'>home</router-link>
<router-link to='/about'>about</router-link>
<router-view></router-view>
</div>
</template>
路由详细配置
- 设置重定向:当用户第一次进入的时候.默认显示的组件
const routes = [ //配置路径和组件之间的映射关系
{
path: '',
//redirect:重定向(设置路由的默认路径)
redirect:'/home'//配置方式一:填写需要展示的组件路径
redirect: {//配置方式二:命名路由
name: 'home'
},
meta: {
title: '主页'
}
},
{
path: '/home',
component: home,
name: 'home',
meta: {
title: '主页'
},
children: [{
path: '',
//redirect:重定向(设置home中默认显示的子组件)
redirect: 'detail',
meta: {
title: '详情页'
}
},
{
path: 'detail',
component: detail,
name: 'detail',
meta: {
title: '详情页'
}
}
]
},
{
path: '/about',
component: about,
name: 'about',
meta: {
title: '关于页面'
}
},
{
path: '*',
//redirect:重定向(设置当URL路径不被路由对象匹配的时候,显示的组件)
redirect: {
name: 'home'
},
meta: {
title: '主页'
}
}
]
{ path: '/dynamic-redirect/:id?',//?的意思就是传不传都行,传我接着,不传我也接着
redirect: to => {
const { hash, params, query } = to
if (query.to === 'foo') {//query传值:/dynamic-redirect?to=foo
return { path: '/foo', query: {
to:query.to
} }
}
if (hash === '#baz') {//hash传值:/dynamic-redirect
return { name: 'baz', hash: hash }
}
if (params.id) {//params传值:/dynamic-redirect/123
return `/with-params/${params.id}`
} else {
return '/bar'//不传值:/dynamic-redirect
}
}
}
- 别名:alias:别名配置有讲究,一般来说有以下几种情况
- 绝对路径别名:'/'+[别名]
{ path: '/root', component: Root, alias: '/root-alias' }//路由模块中定义路由参数
//注意点:如果组件路径是一级路由,那么只能使用绝对路径别名即:'/'+[别名]
<router-link to="/root-alias">//调用:'/'+[别名],但是必须加 '/',没有'/'不行
/root-alias (renders /root)
</router-link>
//注意点:绝对路径别名的优点/缺点是:
//优点:他可以无视层级,无论routes中的item嵌套多少层,都可以直接找到
//缺点:<li><router-link to="/foo">
/root-alias (renders /root)
</router-link></li>//路径上只能写这么一个/foo,写别的不管事,你说气人不!
//总结:绝对路径别名:不能有父别名/父路径,但是可以有子别名/路径(子别名/路径必须是相对路径别名)
//调用的时候:'/'+[绝对路径]
- 相对路径别名:[别名]
{ path: 'bar', component: Bar, alias: 'bar-alias' }//路由模块中定义路由参数
//注意点:相对路径别名,千万不能写写在一级路由上,不然调用不到,切记!
<li><router-link to="/home/bar-alias">//调用[父路径/父别名]+[别名]
/root-alias (renders /root)
</router-link></li>
//总结:router-link调用的使用:'/'+[绝对路径]+[相对路径]+[相对路径]+[相对路径]...
- 数组别名
{ path: 'baz', component: Baz, alias: ['/baz', 'baz-alias'] }//路由模块中定义路由参数
/baz:绝对路径别名调用:/baz
baz-alias:相对路径别名调用:/[父路径/别名]/baz-alias
- 以空字符串作为别名的默认子路由
{ path: 'default', component: Default, alias: '' }//路由模块中定义路由参数
'':相对路径别名:/[父路径/别名]
- 嵌套别名
{ path: 'nested', component: Nested, alias: '/nested-alias',//路由模块中定义路由参数
children: [
{ path: '/foo', component: NestedFoo },//绝对路径别名:调用:/foo
{ path: 'foo', component: NestedFoo }//相对路径别名:/nested-alias/foo
]
}
- 总结绝对路径/相对路径
//注意点:由于编程式导航不能path和params写在同一个对象中,但是如果我写name,别名就不生效了.
//结果:http://localhost:8080/测试/886
//官方说明:/home 的别名是 /测试,意味着,当用户访问 /测试 时,URL 会保持为 /测试,但是路由匹配则为 /home,就像用户访问 /home 一样。
//个人理解:给组件路径换了一个名称,可能为了URL的美观吧,但是用法还是一样的用法,必须保持别名和path的一致性,比如动态路由匹配的时候,也必须要一致,要不然接不到参数.
受到CSS布局'子绝父相'的启发,我将这个绝对路径别名/相对路径别名,也总结一下:
一级路由必须是绝对路径别名,
如果它的嵌套路由中存在绝对路径别名,那么router-link调用的时候,就直接找它嵌套路由中的绝对路径别名即:'/'+[嵌套路由(绝对路径别名)]
如果不存在:'/'+[一级路由(绝对路径别名)]+[相对路径别名]+[相对路径别名]+[相对路径别名]...
注意点:如果是动态路由匹配,必须使用相对路径别名
history模式:默认是hash模式==>http://localhost:8080/#/homeconst router = new VueRouter({ //创建VueRouter对象
routes: routes,
mode:'history'//设置history模式:默认是hash模式==>路径带
});
router-link的属性
to:属性:定义导航的路径<router-link to=[router路由中配置的路径]>home</router-link>
<router-link to='/home'>home</router-link>
tag:属性:定义router-link标签解析成的标签类型(默认是a标签)<router-link to='/home' tag=[domName]>home</router-link>
<router-link to='/home' tag='button'>home</router-link>
replace:属性:定义:history调用的方法,默认是history.pushState():可以触发浏览器的后退功能,加上replace之后,hostory调用的方法是history.replaceState():不能触发浏览器的后退功能<router-link to='/about' replace>about</router-link>
active-class:属性:定义router-link的选中className名称<router-link to='/home' tag='button' replace active-class=[customName]>home</router-link>
<router-link to='/home' tag='button' replace active-class='active'>home</router-link>
- 批量修改
router-link的选中className名称const router = new VueRouter({ //创建VueRouter对象
routes: routes,
mode:'history',
linkActiveClass:'active'//修改所有router-link的选中类名
});
编程式导航
<template>
<div id="app">
<button @click='jumpRouterHome'>home</button>
<button @click='jumpRouterAbout'>about</button>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "App",
methods: {
jumpRouterHome() {
this.$router.push([router中配置的路径]);
this.$router.push("/home");
his.$router.replace([router中配置的路径]);
this.$router.replace("/home");//replace==>history.replaceState()
},
jumpRouterAbout() {
this.$router.push([router中配置的路径]);
this.$router.push("/about");
}
}
};
</script>
- 编程式导航的几种方法
- 字符串
this.$router.push([router中配置的路径]);
this.$router.push("/home");
- 对象
this.$router.push({
path:[router中配置的路径]
});
this.$router.push({
path:"/home"
});
- 命名路由
this.$router.push({
name:[router中name]
});
this.$router.push({
name:"home",
params:{
[动态路由参数]:[值]
}
});
- 带查询参数
router.push({ path: '/register', query: { [查询key]: [查询值] }})
router.push({ name: 'register', query: { [查询key]: [查询值] }})
- router.go(n): history 记录中向前或者后退多少步
// 在浏览器记录中前进一步,等同于 history.forward()
router.go(1)
// 后退一步记录,等同于 history.back()
router.go(-1)
// 前进 3 步记录
router.go(3)
// 如果 history 记录不够用,那就默默地失败呗
router.go(-100)
router.go(100)
动态路由的使用:多个路径匹配到同一个组件中
- 修改
router文件中index.js中的配置const routes = [ //配置路径和组件之间的映射关系
{
path: '/home/:name',//只有一个参数
component: home,
name:'home'
},
{
path: '/about/:id/:userName',//多个参数
component: about,
name:'about'
}
]
- 在
html结构中配置<router-link
to='/home/zhangsan'
tag='button'
replace
>home</router-link>
<router-link
to='/about/886/999'
replace
>about</router-link>
- 编程式导航中配置
this.$router.push({path:`/home/zhangsan`})
this.$router.push({//推荐这种写法,清晰
name:"home",
params:{
userName:'zhangsan'
}
})//注意点:path和params不能在一起配置:不生效
- 取出配置的params
//this.$route当前那个路由处于活跃状态,拿到的就是哪个路由
console.log(this.$route.params)
- 复用组件监听路由变化
- 组件内部watch监听
watch: {
'$route' (to, from) {
// 对路由变化作出响应...
}
}
- 组件内守卫:beforeRouteUpdate
beforeRouteUpdate (to, from, next) {
// react to route changes...
// don't forget to call next()
}
- 捕获所有路由或 404 Not found 路由
{
path: '*',
redirect:{name:'about'}
}
- 高级匹配模式
{ path: '/' },
// 参数用冒号表示:
{ path: '/params/:foo/:bar' },//匹配 /params/参数一/参数二
// 可以通过添加“?”使参数成为可选参数
{ path: '/optional-params/:foo?' },//匹配 /optional-params/参数一 或者/optional-params
// param后面可以跟着params中的regex模式
// 只有当:id是所有号码时,才会匹配此路由
{ path: '/params-with-regex/:id(\\d+)' },//匹配 /params-with-regex/886(必须是纯数字)
// 星号可以匹配任何东西
{ path: '/asterisk/*' },
// 将路径的一部分用括号括起来,然后添加“?”
{ path: '/optional-group/(foo/)?bar' }//匹配 /optional-group/bar 或者 /optional-group/foo/bar
- 匹配优先级
有时候,同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高。
路由懒加载
- 路由懒加载能解决的问题
- 当打包构建应用时,JavaScript包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
- 路由懒加载的主要作用是将路由对应的组件打包成一个个的js文件,只有当这个路由被访问的时候,才会加载对应的js文件
import Vue from 'vue';
import VueRouter from 'vue-router'; //引入插件
Vue.use(VueRouter); //通过Vue.use(插件),安装插件
// import home from '@pages/home/home.vue';
// import about from '@pages/about/about.vue';
const home=()=>import('@pages/home/home.vue');//懒加载的书写方式,这样在打包的时候,生成的js文件,会是一个路由js文件对应一个生成好的js文件
const about=()=>import('@pages/about/about.vue');
const routes = [ //配置路径和组件之间的映射关系
{
path: '/',
//redirect:重定向(设置路由的默认路径)
redirect: '/home/zhangsan'
},
{
path: '/home/:userName',
component: home,
name:'home'
},
{
path: '/about/:userName',
component: about,
name:'about'
}
]
const router = new VueRouter({ //创建VueRouter对象
routes: routes,
mode:'history',
linkActiveClass:'active'
});
export { //导出router
router
}
/**
* 使用vue-router的三个步骤
* 创建路由组件
* 配置路径和组件之间的映射关系
* 使用路由 <router-link>和<router-view>
*/
路由嵌套
//在router文件夹内的index.js中配置
const routes = [ //配置路径和组件之间的映射关系
{
path: '',
//redirect:重定向(设置路由的默认路径)
redirect: '/home'
},
{
path: '/home',
component: home,
name:'home',
children:[
{
path: '',
//redirect:重定向(设置路由的默认路径)
redirect: 'detail'
},
{
path:'detail',
component: detail,
name:'detail'
}
]
},
{
path: '/about',
component: about,
name:'about'
}
]
//在home.vue中配置
<h1>{{msg}}</h1>
<router-link to='/home/detail'>详情</router-link>//配置路径
<router-view></router-view>//配置路由出口
路由的参数传递
params方式:注意点:params的方式,需要在路由中配置动态路由匹配
{//路由配置
path: '/about/:username/path/:post_id',
//path: '/about/:username/:post_id',这样写,不能使用编程式导航,不知道为什么,望指教
component: about,
name:'about'
}
//router-link跳转
<router-link
to='/about/li/path/nan'
replace
>about</router-link>
//编程式导航
this.$router.push({
name:"about",
params:{
username: 'evan', post_id: '123'
}
})
//取:this.$route.params
query:无需路由的特殊配置
<router-link//router-link跳转
:to="{path:'/home',query:{
name:'肖宝成',
age:26
}}"
tag='button'
replace
>home</router-link>
this.$router.push({//编程式导航
name:"home",
query:{
name:'宣传部'
}
})
//取:this.$route.query
路由组件传参
//应用
<div id="app">
<h1>Route props</h1>
<ul>
<li><router-link to="/">/</router-link></li>//Hello Vue! { "foo": "foo" }
<li><router-link to="/hello/you">/hello/you</router-link></li>//Hello you! { "foo": "foo" }
<li><router-link to="/static">/static</router-link></li>//Hello world! { "foo": "foo" }
<li><router-link to="/dynamic/9">/dynamic/1</router-link></li>//Hello 2029! { "foo": "foo" }
<li><router-link to="/attrs">/attrs</router-link></li>//Hello attrs { "foo": "foo" }
</ul>
<router-view class="view" foo="foo"></router-view>
</div>
<template>//hello组件
<div>
<h2 class="hello">Hello {{name}} {{ $attrs }}</h2>
</div>
</template>
<script>
export default {
props: {
name: {
type: String,
default: 'Vue!'
}
}
}
</script>
//路由文件
function dynamicPropsFn (route) {
const now = new Date()
return {
name: (now.getFullYear() + parseInt(route.params.years)) + '!'
}
}
const router = new VueRouter({
mode: 'history',
base: __dirname,
routes: [
{ path: '/', component: about }, // 没有参数,不做事情
{ path: '/hello/:name', component: about, props: true }, // 将匹配出来的动态参数传进去
{ path: '/static', component: about, props: { name: 'world' }}, // 静态值
{ path: '/dynamic/:years', component: about, props: dynamicPropsFn }, // 将静态值与基于路由的值结合
{ path: '/attrs', component: about, props: { name: 'attrs' }}//静态值
]
})
导航守卫
全局前置守卫:写在router文件中
router.beforeEach((to, from, next) => {
console.log(to);//即将要进入的目标 路由对象
console.log(from);//当前导航正要离开的路由
next();//必须调用
next中的参数:
1.next()//什么都不放:进行管道中的下一个钩子
2.next(false) //中断当前的导航
3.next('/') 或者 next({ name: '命名路由' ,params:{})或者next({ path: '/' ,query:{})//跳转到一个不同的地址
4.next(error)// 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调
})
全局解析守卫
router.beforeResolve((to, from, next)=>{//后
console.log('456')
//从from到to
// document.title = to.meta.title;
next();
})
全局后置钩子
//注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身
//对跳转后的页面进行例如滚动条回调0 0 位置、更新页面title、懒加载结束等等
router.afterEach((to, from) => {//最后
document.title = to.meta.title;
// console.log(to);
})
路由独享的守卫
{
path: '/about',
component: about,
name: 'about',
beforeEnter: (to, from, next) => { //路由独享的守卫
console.log(to);
next('/home');
}
}
组件内的守卫
watch: {
$route(to, from) {
//当使用路由参数时,例如从 /user/foo 导航到 /user/bar,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch (监测变化) $route 对象
// 对路由变化作出响应...
console.log(" // 对路由变化作出响应...");
}
}, //监听
beforeRouteEnter(to, from, next) {
//路由进入之前调用
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
//console.log(from);//上一个激活的路由
//console.log(to);//当前路由
next(vm => {
// 通过 `vm` 访问组件实例
console.log(vm)//当前激活的路由对应的组件对象
});
// next();
},
beforeRouteUpdate(to, from, next) {
//路由更新调用
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
// console.log(to);
next();
},
beforeRouteLeave(to, from, next) {
//这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
//to是将要去的路由
//from是将要离开的路由(也就是当前的路由)
const answer = window.confirm(
"Do you really want to leave? you have unsaved changes!"
);
if (answer) {
next();
} else {
next(false);
}
},
完整的导航解析流程
1.导航被触发。
2.在失活的组件里调用离开守卫。//beforeRouteLeave (组件内调用)
3.调用全局的 beforeEach 守卫。//beforeEach (router.js内调用)
4.在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。//beforeRouteUpdate (组件内调用)
5.在路由配置里调用 //beforeEnter路由独享的守卫 (router.js内调用)
6.解析异步路由组件。
7.在被激活的组件里调用 //beforeRouteEnter (组件内调用)
8.调用全局的 //beforeResolve (router.js内调用)
9.导航被确认。
10.调用全局的 afterEach 钩子。//afterEach (router.js内调用)
11.触发 DOM 更新。
12.用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。//beforeRouteEnter