vue-router使用教程

vue-router的使用教程

路由

路由就是,根据地址栏的路径,返回对应的页面

后端路由

node.js写法

1
2
3
4
5
6
7
8
9
if(path === '/'){
返回主页
}else if(path==='/page1'){
返回page1
}else if(path==='/page2'){
返回page2
}else {
返回404
}

前端路由

vue-router写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const routes = [
{ path: '/page1', component: Page1 },
{ path: '/page2', component: Page2 }
]
```
# 基础使用
```html
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/page1">Go to page1</router-link>
<router-link to="/page2">Go to page2</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将塞到这里渲染出来 -->
<router-view></router-view>
</div>

router-link默认渲染成带有正确链接的a标签,可以通过配置 tag 属性生成别的标签.。参考文档


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//使用vue-router
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
//1. 定义组件
const Page1 = { template: '<div>这里是页面1</div>' }
//也可以通过 import 导入进来
import Page2 from './components/Page2.vue'
// 2. 配置路由
const routes = [
{ path: '/page1', component: Page1 },
{ path: '/page2', component: Page2 }
]
// 3. 创建 router 实例,然后将配置 `routes` 传入
const router = new VueRouter({
routes // (缩写)相当于 routes: routes
})
// 4. 将router传给app
const app = new Vue({
router,
el:'#app',
});

routes配置选项

例子2

1
2
3
4
5
6
7
8
9
<div id="app">
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/">首页</router-link>
<router-link to="/about">关于我们</router-link>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//配置路由
const routes = [{
path: '/',
component: {
template: `<div><h1>这里是首页</h1></div>`,
},
}, {
path: '/about',
component: {
template: `<div><h1>这里是关于我们</h1></div>`,
},
}, ];
//将配置好的路由传给实例
const router = new VueRouter({
routes // (缩写) 相当于 routes: routes
});
const app = new Vue({
el:'#app',
router,
});

【查看在线实例】

路由传递参数(动态路由匹配)

文档:动态路由匹配

路径参数params

path:'/user/:username',则this.$route.params.username就是user/后面的值
地址栏显示为:localhost:8080/#/user/王花花

直接传递参数

1
<router-link to="/user/王花花">王花花</router-link>

或者通过nameparams传递路径参数

1
2
3
4
<router-link :to="{name:'UserName', params:{username:'王花花'}}">王花花</router-link>
<!-- 不能用path,否则报错!!!!必须用 name -->
<router-link :to="{path:'/user', params:{username:'王花花'}}">王花花</router-link>

“路径参数”使用冒号 : 标记。当匹配到一个路由时,参数值会被设置到 this.$route.params,可以在每个组件内使用。

1
2
3
4
5
6
7
8
9
10
//配置路由
const routes = [{
// 动态路径参数 以冒号开头
path: '/user/:username',
name:'UserName',
component: {
//通过$route.params.username获取路径参数
template: `<div><h1>我叫 {{$route.params.username}}</h1></div>`,
},
}, ];

查询参数query

/xxx?a=1&b=2,则this.$route.query就是问号后面的内容
地址栏显示为:localhost:8080/#/user/王花花?age=20

直接传递参数

1
<router-link to="/user/王花花?age=20">王花花</router-link>

或者通过name / pathquery传递参数

1
2
3
4
<router-link :to="{name:'UserName',query:{xxx:123}}">王花花</router-link>
<!-- 等同于 -->
<router-link :to="{path:'/user/王花花',query:{xxx:123}}">王花花</router-link>

通过$route.query.xxx获取查询参数

1
2
3
4
5
6
7
8
9
//配置路由
const routes = [{
// 动态路径参数 以冒号开头
path: '/user/:name',
name:'UserName',
component: {
template: `<div><h1>我叫 {{$route.params.name}}</h1><h2>我今年{{$route.query.age}}岁了</div>`,
},
}, ];

【查看在线实例】

嵌套路由(子路由)

在配置routes时添加 children

1
2
<router-link to="/user/王花花">王花花</router-link>
<router-link to="/user/李栓蛋">李栓蛋</router-link>

!注意:children里path前不要加/
可以使用append在路径后面追加more,但是append每次点击会重复追加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//配置路由
const routes = [{
// 动态路径参数 以冒号开头
path: '/user/:name',
component: {
template: `<div><h1>我叫 {{$route.params.name}}</h1>
//↓由于是动态路径,所以这里是:to,不要漏了冒号
<router-link :to="'/user/'+$route.params.name+'/more'">更多信息</router-link>
<router-view></router-view>`,//或者使用append,追加more这一页
},
//子路由是个数组,如果有多个同级子路由,则写在一个数组里
children:[
{
path:'more',//这里不要写成'/more'
component:{
template:`<div><h3>用户{{$route.params.name}}的信息</h3>loremloremloremlorem</div>`,
},
}
],
}, ];

【查看在线实例】

!注意:记得给父路由里router-view,否则子路由没有出口展示

通过命名路由可以简化路径的写法

原本的路径是/user/王花花

1
<router-link to="/address/form">编辑地址</router-link>

通过命名路由

1
2
3
4
5
6
7
8
9
10
children: [{
path: 'choose',
name:'choose',
component: ChooseAddress,
},
{
path: 'form',
name:'form',
component: AddressForm,
}]

可以将router-link简写成

1
<router-link :to="{ name: 'form'}">User</router-link>

router-link相关api

编程式导航

除了使用 <router-link> 创建 a 标签来定义导航链接,有时我们想点击一个按钮来切换页面,这时可以给按钮绑定@click=$router.push('/xxx'),借助 router 的实例方法,通过编写代码来实现。
$router.push(location, onComplete?, onAbort?)
注意:在 Vue 实例内部,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push
$router的相关方法:https://router.vuejs.org/zh/api/#router-aftereach

1
2
3
<div id="app">
<router-view></router-view>
</div>

可以使用$router.push('/index'),如果有参数的话,可以使用 $router.push({name:'index',params:{userId:12345}}) 或者$router.push(\/index/${userId}`)`

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//1. 定义组件
const Login = { template: `
<div>登录界面
<button @click="$router.push('/')">返回</button>
</div>`
};
const Index = {
template: '<button @click="login">登录</button>',
methods:{
login(){
this.$router.push('/login');
},
},
};
// 2. 定义路由
const routes = [
{ path: '/', component: Index },
{ path: '/login', component: Login },
{ path: '*', component: NotFound } //放到最后面
];
// 3. 创建 router 实例,然后传 `routes` 配置
const router = new VueRouter({
routes // (缩写)相当于 routes: routes
});
// 4. 将router传给app
const app = new Vue({
router,
el:'#app',
});

【查看在线实例】

1
2
3
4
<router-link
:to="{name: 'form', query: { type: 'add' }}">
新增地址
</router-link>

等同于

1
2
3
addAddress(){
this.$router.push({name: 'form', query: { type: 'add' }})
}

router-push

命名路由(给routes取名字name)

有时候,通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。你可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。

1
2
3
4
5
//配置路由
const routes = [
{ path: '/user', name:'user', component: User },
{ path: '/login', name:'login', component: Login }
];

要链接到一个命名路由,可以给 router-link 的 to 属性传一个对象:

1
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>

这跟代码调用 router.push() 是一回事:

1
$router.push({ name: 'user', params: { userId: 123 }})

这两种方式都会把路由导航到 /user/123 路径。

命名视图(多个出口取名字)

文档:命名视图

有时候想在同一个页面上同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar (侧边栏) 和 content (主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default所对应的组件。

1
2
3
4
5
6
7
8
9
10
11
12
const router = new VueRouter({
routes: [
{
path: '/',
components: {
default: TopNav,
a: Content,
b: SideBar
}
}
]
})
1
2
3
<router-view class="default" />
<router-view class="content" name="a" />
<router-view class="sidebar" name="b" />

重定向(跳转)

文档:重定向

当访问 /a时, 重定向到 /b

1
2
3
4
5
//配置路由
const routes = [
{ path: '/a', redirect: '/b' },
{ path: '*', redirect: '/'} //当匹配不到路由时,重定向到首页
]

重定向的目标也可以是一个命名的路由:

1
2
3
const routes = [
{ path: '*', redirect: { name: 'index' }}
]

路由按顺序从上到下,依次匹配。最后一个*能匹配全部,因此要放在最后面!!!

响应路由参数的变化

当使用路由参数时,例如从 /user/王花花 导航到 /user/李栓蛋,由于路径都是/user/:username,因此页面不会更新数据。想对路由参数的变化作出响应的话,你可以在组件中通过 watch (监测变化) $route 对象

1
2
3
4
5
6
7
8
9
//组件中
export default {
watch: {
'$route'(to, from) {
//当$route发生变化时,获取最新的数据
this.getData();
}
}
}

导航守卫/导航钩子(路由改变时进行验证)

“导航”表示路由正在发生改变。

全局守卫文档:全局守卫

1
2
<router-link to="/login">登录</router-link>
<router-link to="/admin">后台管理</router-link>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const router = new VueRouter({ ... })
//全局守卫
router.beforeEach((to, from, next) => {
//console.log(to);
//console.log(from);
let logined=false;
//如果要前往admin页面,且处于未登录状态
if(to.path =='/admin' && !logined){
//则跳转到登录页
next('/login');
}else{
next();
}
})

router.beforeEach:当路由改变之前

to、from都是路由对象,相关api参考路由对象API

  • next():正常导航
  • next(false):禁止导航
  • next('/xxx'):中断当前导航,跳转到/xxx

【查看在线实例】

路由元信息及匹配

导航守卫里,验证方式太过单一

1
2
3
4
5
6
7
8
9
if(to.path =='/admin' && !logined){
//则跳转到登录页
next('/login');
}else{
next();
}
在未登陆状态时,如果要前往/admin,则会跳转到/login页面
!但是,如果要前往/admin/db,仍然可以前往,即使在未登录状态下

如何在未登录状态下,/admin/admin下面的所有内容都无法访问?
我们可以在定义路由的时候可以配置 meta 字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//配置路由
const routes = [{
path: '/login',
component: {
template: `<h1>请先登录</h1>`,
},
},
{
path: '/admin',
meta:{
logined:false,
},
component: {
template: `<div>
<h1>管理员页面</h1>
<router-link to="/admin/db">数据库</router-link>
<router-view></router-view>
</div>`,
},
children:[
{
path:'db',
component:{template:`<h2>这里是数据库</h2>`},
}
],
},
{
path: '/admin2',
meta:{
logined:false,
},
component: {
template: `<h1>这里是另一个管理员页面</h1>`,
},
}];

那么如何访问这个 meta 字段呢?
通过路由对象(to、from都是路由对象)的matched属性,得到路由配置routes里的路由记录(是个数组);再通过.some()方法遍历这个数组下的meta字段

1
2
3
4
5
6
7
8
9
10
11
//全局守卫
router.beforeEach((to, from, next) => {
console.log(to.matched);
//遍历路由对象,检查里面的meta信息
//some() 方法用于检测数组中的元素是否满足指定条件,满足返回true,不满足返回false
if(to.matched.some(item=>item.meta.logined)){//此处为判断item.meta.logined===true的简写形式
next();
}else{
next('/login');
}
})

【查看在线实例】

meta的详细用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import store from '@/store';//引入vuex
const router = new Router({
routes: [
{
path: '/',
name: 'index',
component: () => import(/* webpackChunkName: "index" */ '@/pages/index/Index.vue'),
meta: {
requireLogin:true //需要验证登录状态
}
}
]
})
router.beforeEach((to,from,next) =>{
if(to.matched.some(record => record.meta.requireLogin)){//如果该路由需要验证登录状态
if(!store.state.auth.isLogin){//如果没有登录
next({//跳转到登录页
path:'/login',
query: { redirect: to.fullPath },//查询参数显示:从哪儿跳转而来,这样登录以后,可以从查询参数得到路径设置跳转回去
});
} else{//如果已经登录
next();
}
} else{//如果不需要验证登录状态,则直接跳转
next();
}
})

如果是异步操作,可能还未获取到状态,就已经跳转了,因此异步验证异步状态需要改写成这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
router.beforeEach((to,from,next) =>{
if(to.matched.some(record => record.meta.requireLogin)){//如果该路由需要验证登录状态
store.dispatch('checkLogin').then(isLogin=>{ //从vuex获取登录状态后,再跳转
if(!isLogin){
next({
path:'/login',
query:{redirect:to.fullPath}
});
} else{
next();
}
})
} else{
next();
}
})

然后在登录页设置一下,让它登录后跳转回原来的页面

1
2
3
4
5
6
7
clickLoginBtn(){
this.$request(.......)
.then(()=>{
this.$router.push({path: this.$route.query.redirect || '/'})
//或者 this.$router.back();
})
}

懒加载

路由懒加载
默认情况下,会将所有路由下的组件都打包在一个js文件下,文件体积太大。懒加载的作用是,将每个路由对应的组件分开打包成独立的js文件,只有当你跳转到该路由时,才加载相应的组件。

1
2
3
4
5
6
7
const Home = () => import('./Home.vue');
const router = new VueRouter({
routes: [
{ path: '/home', component: Home }
]
})

这样,Home组件会被打包成独立的js文件,只有跳转到/home时才加载

把组件按组分块

1
2
3
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')

这3个组件会被打包到同一个js文件里,当跳转到相应路由时,这3个组件一起加载
webpackChunkName用来指定生成的js文件的文件名,否则 `chunkFilename: “[name].[chunkhash:8].chunk.js” 中的 [name] 是一个自动分配的、可读性很差的id

最后,配置一下webpack,使其打包的js文件名不是随机乱码

router-view配合过渡动画/动态组件

确保使用顺序,最外层过渡动画,然后动态组件,最后router-view

1
2
3
4
5
<transition>
<keep-alive>
<router-view></router-view>
</keep-alive>
</transition>

!!主要,<router-view></router-view> 不能写成 <router-view />

$router vs $route

$router用于设置路由【$router里面是方法】

https://router.vuejs.org/zh/api/#router-%E5%AE%9E%E4%BE%8B%E5%B1%9E%E6%80%A7

  • $router.push
  • $router.replace
  • $router.go
  • $router.back
  • $router.forward
  • $router.beforeEach

路由对象$route,用于获取路由信息【$route里面是属性】

https://router.vuejs.org/zh/api/#%E8%B7%AF%E7%94%B1%E5%AF%B9%E8%B1%A1

  • $route.path
  • $route.params
  • $route.query
  • $route.fullPath
  • $route.name
  • $route.meta
-------------本文结束感谢您的阅读-------------