0%

【Vue】vue-router前端路由

关于前端路由的讲解,前端路由的讲解暂时以cli2.x进行


一、前后端渲染和路由

1.1 后端路由阶段

  • (1)后端渲染

    • jsp / php,通过html+css+java技术,在后端(服务器)渲染页面,然后发送给用户
  • (2)后端路由:后端处理URL和页面之间的映射关系

    • 缺点:整个页面都是交给后端来处理

1.2 前后端分离阶段

  • 后端只负责提供数据,不负责任何前端页面的内容
  • 前端渲染:
    • 浏览器中显示的页面中大部分内容,都是前端些的js代码在浏览器中执行,最终渲染出来的页面

1.3 单页面富应用阶段

  • 简称SPA(single page application)
    • 特点:在前后端分离的基础上,加了一层前端路由

二、URL变化页面不刷新

2.1 hash值

2.2 HTML5history模式

  • (1)pushState()
  • 因为pushState()本质是将路由url存放在栈里,所以可以执行以下操作
  • (2)history.back()
    • 返回上一页面
  • (3)history.forward()
    • 进入下一页面
  • (4)history.go(-1) == history.back()
  • (5)history.go(1) == history.forward()

三、vue-router安装和配置

3.1 安装

  • (1)webpack项目:
    • npm install vue-router --save
  • (2)vue cli项目
    • 创建的时候选择vue-router即可

3.2 配置路由

  • (1)webpack项目:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //创建一个router文件夹进行管理
    //在router文件夹创建index.js进行配置

    //配置路由的相关信息
    import Vue from 'vue' //导入Vue
    import Router from 'vue-router' //导入路由插件

    Vue.use(Router) //安装路由插件

    const routes = []; //配置路由跳转信息

    const router = new Router({
    routes //es6语法 routes: routes
    });

    export default router; //导出
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //在main.js使用路由
    import Vue from 'vue'
    import App from './App'
    import router from './router/index.js' //导入,可以省略/index,会自动寻找index文件

    new Vue({
    el: '#app',
    router, //挂载路由,es6语法
    render: h => h(App)
    })
  • (2)vue cli项目

    • 默认设置即可

四、路由映射配置

4.1 创建路由组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div>
<h2>我是首页</h2>
</div>
</template>

<script>
export default {
name: "home"
}
</script>

<style scoped>

</style>

4.2 配置路由映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import Vue from 'vue' 
import Router from 'vue-router'
import Home from "../components/home" //导入组件

Vue.use(Router)

//配置路由映射,一个映射对应一个对象
const routes = [
{
path: "/home", //路径
component: Home //映射的组件
}
]

const router = new Router({
routes
});

export default router;

4.3 首页设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div id="app">
<router-link to="/home">首页</router-link> <!--路由映射链接标签-->
<router-view></router-view> <!--接收路由组件内容,和组件开发slot插槽类似-->
</div>
</template>

<script>
export default {
name: 'App'
}
</script>

<style>
</style>

4.4 配置默认路径

1
2
3
4
5
6
7
8
9
10
11
//router/index.js
const routes = [
{
path: "/",
redirect: '/home' //重定向到首页
},
{
path: "/home",
component: Home
}
]

4.5 使用history模式

  • vue-router路由跳转,默认使用hash跳转,所以页面会出现localhost:8080/#/home,为了去掉’#’,可以使用history模式
1
2
3
4
5
// router/index.js
const router = new Router({
routes,
mode: 'history'
});

五、router-link属性补充

5.1 tag属性

1
<router-link to="/home" tag="button">首页</router-link> 
  • 页面最终渲染<router-link>标签默认为<a>标签,可以通过tag属性修改要渲染的标签

5.2 replace属性

1
<router-link to="/home" tag="button" replace>首页</router-link> 
  • 如果该前端路由使用history模式,但是不想该页面跳转可以返回,用replace来禁止页面返回跳转

5.3 active-class属性

  • <router-link>标签被点击时,会在class产生一个’router-link-active’属性,可以通过该属性来设置点击时的样式,但是如果嫌名称过长,可以通过active-class来进行修改
1
<router-link to="/home" tag="button" replace active-class="active">首页</router-link>
  • 如果修改的router-link标签过多,可以在router的index.js进行统一设置
1
2
3
4
const router = new Router({
routes, //es6语法
linkActiveClass: 'active' //统一修改active-class
});

六、路由代码跳转

  • 我们可以不使用<router-link>标签,通过其他标签,监听点击,在方法中通过代码实现路由跳转
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- App.vue -->
<template>
<div id="app">
<button @click="homeClick()">首页</button>
<router-view></router-view>
</div>
</template>

<script>
export default {
name: 'App',
methods: {
homeClick() {
//push 和 replace都可以,只是能不能返回的问题而已
// this.$router.push("/home");
this.$router.replace("/home");
}
}
}
</script>

<style>
</style>

七、动态路由

  • 前端路由跳转时,跳转的参数时不确定的,动态的实现方法

7.1 搭建基础的路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!--创建 components/user.vue-->
<template>
<div>
<h2>我是用户</h2>
</div>
</template>

<script>
export default {
name: "user"
}
</script>

<style scoped>

</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// router/index.js,配置路由映射
import Vue from 'vue' //导入Vue
import Router from 'vue-router' //导入路由插件
import User from "../components/user"

Vue.use(Router) //安装路由插件

const routes = [
{
path: "/user",
component: User
}
]

const router = new Router({
routes,
mode: 'history',
});

export default router;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--./App.vue:设置首页-->
<template>
<div id="app">
<router-link to="/user" replace tag="button">用户</router-link>
<router-view></router-view>
</div>
</template>

<script>
export default {
name: 'App'
}
}
</script>

<style>

</style>

7.2 进行动态设置

1
2
3
4
5
6
7
8
9
10
//修改./router/index.js

...
const routes = [
{
path: "/user/:userName", //':userName',动态接受数据
component: User
}
]
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--修改 ./App.vue-->
<template>
<div id="app">
<router-link :to="'/user/' + userName" replace tag="button">用户</router-link> <!--使用v-bind 绑定数据-->
<router-view></router-view>
</div>
</template>

<script>
export default {
name: 'App',
data() {
return {
userName: "莱特雷" //创建数据
}
}
}
</script>
...
1
2
3
4
5
6
7
8
<!--修改 ./components/user.vue 接受数据-->
<template>
<div>
<h2>我是用户</h2>
{{$route.params.userName}} <!--接受动态数据,注意是'$route',不是'$router'-->
</div>
</template>
...

八、路由懒加载

8.1 打包目录解析

8.2 懒加载认识

  • 因为打包时会把所有业务代码打包在一个app的js文件上,会导致文件巨大,加载该文件时,可能会出现短暂的空白
  • 使用懒加载,将不同路由组件打包成不同的代码块,用户访问到该路由时再加载,用户体验上升

8.3 懒加载使用

  • (1)写法一
    • 结合Vue异步组件和Webpack代码的分析(旧)
1
2
3
4
5
const Home = resolve => {
require.ensure(['..componets/Home.vue'], () => {
resolve(require('../components/Home.vue'))
})
}
  • (2)写法二
    • AMD写法
1
const Home = resolve => require(['../components/Home.vue'], resolve)
  • (3)写法三
    • ES6写法,组织Vue异步组件和Webpack的代码分割
1
const Home = () => import('..components/Home.vue')

8.4 例子改写和打包结果

1
2
3
4
5
6
7
8
// import Home from "../components/home"
const Home = () => import("../components/home");

// import About from "../components/about"
const About = () => import("../components/about");

// import User from "../components/user"
const User = () => import("../components/user");
  • 打包结果

九、路由嵌套

  • 在home的页面下创建一个子路由”/home/news”

9.1 创建组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ./components/homeNews.vue
<template>
<div>
<h3>这里是新闻哦!</h3>
</div>
</template>

<script>
export default {
name: "homeNews"
}
</script>

<style scoped>

</style>

9.2 路由注册

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
...
const HomeNews = () => import("../components/homeNews")

...
const routes = [
{
path: "/",
redirect: '/home'
},
{
path: "/home",
component: Home,
children: [ //子路由
{
path: "",
redirect: "news" //默认路径
},
{
path: "news", //子路径不要添加'/',否则识别不出来
component: HomeNews
}
]
}
]
...

9.3 home页面修改

1
2
3
4
5
6
7
8
<template>
<div>
<h2>我是首页</h2>
<router-link to="/home/news" tag="button">新闻</router-link> <!--跳转子路由-->
<router-view></router-view> <!--显示子路由信息-->
</div>
</template>
...

十、参数传递

10.1 动态路由的方式

  • 动态路由在上面有说,就不在此再讲

10.2 query类型

  • (1)搭建一个’profile’路由
1
2
3
4
5
6
7
<!-- 创建:./components/profile.vue --->
<template>
<div>
<h2>这里是profile组件</h2>
</div>
</template>
...
1
2
3
4
5
6
7
8
9
10
11
// 注册路由: ./router/index.js
const Profile = () => import("../components/profile");
...

const routes = [
...
{
path: "/profile",
component: Profile
}
]
1
2
3
4
5
6
7
8
9
<!-- 修改首页: ./App.vue -->
<template>
<div id="app">
...
<router-link to="/profile" tag="button">档案</router-link>
<router-view></router-view>
</div>
</template>
...
  • (2)参数传递
1
2
3
4
5
6
7
8
9
10
<!-- 修改首页: ./App.vue -->
<template>
...
<!--利用v-bind将to交给vue管理,传递一个对象,path为跳转路径,query为传递参数的对象-->
<router-link :to="{path: '/profile', query: {name: '莱特雷', age: 18, sex: '男'}}" tag="button">档案</router-link>
<!--页面结果:http://localhost:8080/profile?name=莱特雷&age=18&sex=男,类似后端的get请求-->
<router-view></router-view>
</div>
</template>
...
  • (3)参数接收
1
2
3
4
5
6
7
8
9
10
11
<!-- 修改profile文件: ./components/profile.vue -->
<template>
<div>
<h2>这里是profile组件</h2>
<h3>{{$route.query}}</h3> <!--提取对象-->
<h3>{{$route.query.name}}</h3> <!--提取对象属性-->
<h3>{{$route.query.age}}</h3>
<h3>{{$route.query.sex}}</h3>
</div>
</template>
...

十一、全局导航守卫

  • 实现功能:在每次页面跳转时,修改当前标题为当前页面名称

11.1 利用生命周期函数实现

  • created():在页面生成时,会自动调用此函数,利用此来进行修改页面标题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--举例:./components/about.vue-->
<template>
<div>
<h2>我是关于</h2>
</div>
</template>

<script>
export default {
name: "about",
created() {
document.title = "关于"
}
}
</script>

11.2 利用全局导航守卫

  • (1)函数源码分析
  • 利用路由器对象的beforeEach()方法进行使用全局导航守卫,路由跳转时会使用自动调用此函数
1
2
3
4
5
6
7
8
beforeEach(guard: NavigationGuard): Function
||跳转NavigationGuard

export type NavigationGuard<V extends Vue = Vue> = ( //箭头函数,参数为to, from, next
to: Route, //跳转目标路由
from: Route, //跳转处罚路由
next: NavigationGuardNext<V> //执行导航守卫下一步
) => any
  • (2)使用全局导航守卫实现需求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//给每个路由添加一个标题原数据 ./router/index.js
const routes = [
{
path: "/",
redirect: '/home'
},
{
path: "/home", //路径
component: Home, //映射的组件
meta: {
title: "首页"
}
}
...以此类推
]
1
2
3
4
5
6
7
8
9
10
//使用beforeEach()函数 ./router/index.js
const router = new Router({
routes
});

router.beforeEach((to, from, next) => {
//document.title = to.meta.title; 对于使用嵌套路由的页面获取不了数据
document.title = to.matched[0].meta.title;
next(); //必须要先执行下一步,否则程序会暂停在此
})

11.3 全局导航守卫补充

  • (1)全局守卫处理beforeEach之外,还有afterEach,分别在路由跳转前/路由跳转后执行
1
2
3
4
//通过afterEach实现需求

router.afterEach((to, from) => document.title = to.matched[0].meta.title);
//不需要next参数,并且不需要调用

十二、keep-alive

  • keep-alive 是Vue内置的一个组件,可以是被包含的组件保留状态,或避免重新渲染
  • route-view也是一个组件,如果直接被抱在keep-alive里面,所有的路径匹配到的视图组件都被缓存,不会立即销毁

12.1 keepp-alive实现功能

  • 需求,点击首页的子路由时,记录点击的子路由,返回首页时,自动跳转到该子路由,而不是默认了的子路由
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 主页面添加keep-alive:./App.vue -->
<template>
<div id="app">
<router-link to="/home" tag="button" replace active-class="active">首页</router-link>
<router-link to="/about" tag="button" replace active-class="active">关于</router-link>
<router-link :to="'/user/' + userName" replace tag="button">用户</router-link> <!--使用v-bind 绑定数据-->
<router-link :to="{path: '/profile', query: {name: '莱特雷', age: 18, sex: '男'}}" tag="button">档案</router-link>
<!--添加keep-alive 缓存路由内容-->
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- 修改首页: ./components/home.vue -->
<script>
export default {
name: "home",
data() {
return {
path: "/home/news" //记录路径
}
},
//注意:activated只有使用keep-alive标签包裹后才会生效
activated() {
this.$router.replace(this.path); //首页被激活时,跳转路径
},
//组件守卫
beforeRouteLeave(to, from, next) {
this.path = from.path; //页面跳转时,记录当前路径,下一次页面激活时,跳转该路径
next();
}
}
</script>