1. 前后端路由的来历
  2. 前端如何实现页面跳转但是不刷新?

    了解hash和history两种方法
  3. vue-router基本使用
    • 安装vue-router

    • 搭建vue-router框架的步骤

    • vue-router路由的配置步骤

      • 第一步: 创建路由组件
      • 第二步: 配置路由映射。 即:组件和路由的关系
      • 第三步: 使用路由, 通过<router-link>和<router-view>来展示组件
    • 路由的默认配置

    • 修改静态路由的模式为history

    • vue-link属性设置

    • 通过代码跳转路由

    • 动态路由的使用

    • 路由的懒加载

  4. vue-router的嵌套
  5. vue-router参数传递
  6. vue-router导航守卫
  7. keep-alive

说道路由, 我们最熟悉的路由是什么呢? 那就是路由器了。 其实路由器有两个重要的功能: 路由和传送

  • 路由: 路由决定数据包从哪里来, 到哪里去。 也有是来源和目的地的路径。

      路由中有一个路由表, 路由表本质上就是一个映射表,决定了数据包的传输方向。
  • 传送: 传送是将输入端的数据传送给输出端

下面我们先来搭建一个项目, 然后一边学习一遍在项目里实战

创建vue-cli2项目

vue init webpacek vueroute

然后一路向下就可以了, 如果本地创建项目很慢, 可以采用离线创建项目的方式, 具体步骤:

  1. 下载webpack离线模板: https://github.com/vuejs-templates/webpack
  2. 将下载的模板压缩包解压,修改文件名为wepback并放入到/Users/自己电脑的用户名/.vue-templates文件夹中.
  3. 执行创建项目的命令: vue init webpack --offline

一. 前后端路由的来历

前后端路由, 目前经历了三个阶段, 哪三个阶段呢?

  1. 前后端一体(后端路由)阶段: 这个阶段类似早起的jsp页面, 和java页面混合在一起, jsp里面有css, js, 还有java代码, 前后端都是混合在一起的.

    缺点很明显, 前后端分工不明确.

    这种方式采用的是后端路由

    基本流程: 请求一个controller接口 --> 通过接口找到页面 --> 渲染页面 --> 返回给浏览器

  2. 前后端分离阶段: 前端通过ajax调用的形式, 调用后台接口. 前端主要负责页面渲染, 后端主要提供api接口.

    优点: 前后端分离. 各司其职, 分明明确. API可复用性强, fe, android, ios都可用

    此时用户请求的就是一个html页面, 页面需要哪个url了, 直接通过ajax请求到页面.

    基本流程: 浏览器url请求 -> html页面 -> ajax请求api接口 -> 后台接口响应数据 -> html页面渲染 -> 返回给浏览器

  3. 单页面富应用阶段: 简称SPA, 全称是simple page application. 最主要的特点是在前后端分离的基础上加了一层前端路由. 这个路由是有前端来维护的一套路由.

    单页面指的是:一个html文件 + 一个js文件 + 一个css文件.

可是就一个网站来说, 不可能只有一个页面. 那么是如何实现的呢?我们来看下图

前端只有一个页面index.html, 而各个功能都是一个组件, 将所有组件都放到index.html页面中, 然后根据用户的请求定位到某一个组件. 这个是谁来定位的呢?就是前端路由来定位, 在vue中前端路由就是vue-router.

前端路由的核心是什么呢? 改变url, 但是页面不进行整体刷新.

二. 前端如何实现页面跳转但是不刷新?

前面说了, vue使用的是单页面富应用, 也就是一个index.html就是整个项目, 然后在内部在跳转链接的时候, 不会刷新页面, 实现这种方式有两种方法:hash和history

这两种模式都可以实现页面跳转,但是不刷新页面. 他们如何使用, 又有什么区别呢?

1. hash

首先启动vue项目

vue init dev

然后打开页面

localhost:8080

在浏览器控制台输入localhost.hash="about", 我们可以看到页面链接变成了localhost:8080/#/about/

如上图, 我们可以通过location.hash="链接"的方式来修改url,但是并不刷新页面

2. history

除了使用hash,我们还可以使用history来改变实现改变url但不刷新页面的方法. history有几个常见的用法.

  1. history.pushState(state,"title","url")

    向浏览器新增一条历史记录,但是不会刷新当前页面(不会重载)
  • state为对象,可以用作携带信息用,
  • title:目前来看没啥用一般为空或null,
  • URL:即要更改页面的URL,且必须同源,不能跨域;

案例: 我们在vue的浏览器界面改变http://localhost:8080为http://localhost:8080/about

如上图所示: 当我们执行history.pushState({a:1},null,"about");的时候, 浏览器并没有刷新页面(Network没有请求), 但是url链接确实发生了变化

  1. history.replaceState(state,title,URL)

更改当前浏览器的历史记录,即把当前执行此代码页面的记录给替换掉,参数与第一条相同

  1. history.back()、history.forward()、history.go()

    分别为前进一个历史,后退一个,history.go(Number),其中Number可正可负,即向前或向后若干个记录

案例:

如上图, 当我们使用history.back()命令的时候, 会回退到上一个页面, 也并没有发生更新.

  1. history.state

    返回当前页面状态参数,此参数一般由history.pushState(state,title,URL);以及history.replaceState(state,title,URL);附带的state值,例子如下:

案例:

如上图: 可以看出history.state就是取出了pushState和replaceState两个命令中的第一个参数

  1. history.length

    返回当前页面所产生的历史记录个数,即在同一个浏览器tab下产生的历史记录;
  1. history事件onpopstate
window.onpopstate = function(e){
console.log(e.state);
}

在history.back(),history.forward(),history.go()时触发此事件,但是在history.pushState();history.replaceState();时并不会触发此事件,事件内可以获取到state状态值

可以看出vue-router中push()、go()等函数是基于hash和histroy的,但是vue-router比这个要复杂.

三. vue-router基本使用

vue-router是Vue.js官方的路有插件, 他和vue.js是深度集成的.适合构建于单页面富应用.

vue-router官网: https://router.vuejs.org/zh/

  • vue-router是基于路由和组件的: 路由用于设定访问路径, 将路径和组件映射起来
  • 在vue-router的单页面应用中, 页面的路径的改变就是组件的切换.

1. 安装vue-router

npm install vue-router --save

--save: 表示在构建以后也要使用这个路由

安装好以后, 在package.json中就可以看到安装的vue-router的版本了

并且在src目录下多了一个文件夹router

2. 搭建vue-router框架的步骤

在我们安装了vue-router以后,就会在src目录下自动生成一个文件夹router.

我们在里面创建一个index.js文件, 然后开始配置路由相关的信息

  • 第一步: 导入路由对象,并且调用vue.use(VueRouter)

    安装了vue-router, 要想使用, 还需要先引入路由对象
import Router from 'vue-router'

vue-router是一个插件, 所以, 我们需要使用vue.use(插件名) 来安装插件

Vue.use(Router)
  • 第二步: 创建路由实例,并且传入路由映射配置

    在VueRouter中主要是配置路由和组件之间的映射关系的.
const routes = [

]
const router = new VueRouter({
// 这里配置的是路由和组件的映射关系, 是一个数组.
routes
})

在这里路由是空的, 还没有配置任何映射关系.

  • 第三步: 将vue-router实例对象导出
export default router
  • 第四步: 在vue实例中挂载创建的路由实例
import router from './router'

在import目录的时候, 有一个默认的规则, 那就是如果你导入一个目录, 比如./router, 没指定导入哪一个文件, 他会自动导入index.js文件*

然后在vue实例中引入router

new Vue({
el: '#app',
// 然后通过router导入vue路由
router,
render: h => h(App)
})

3. vue-router路由的配置步骤

  • 第一步: 创建路由组件

    通常, 我们会在components目录下创建组件。鼠标右击-> Vue Component, 然后定义组件内容

    我们创建两个组件, 一个首页, 一个关于页面.

首页

<template>
<div>
<h2>这是Home主页</h2>
<div>欢迎来到home主页</div>
</div>
</template> <script>
export default {
name: "Home"
}
</script> <style scoped>
</style>

关于页面

<template>
<div>
<h2>关于页面</h2>
<div>欢迎来到关于页面</div>
</div>
</template> <script>
export default {
name: "About"
}
</script> <style scoped> </style>

这样组件就创建好了。

  • 第二步: 配置路由映射。 即:组件和路由的关系

组件创建好了, 接下来要构建组件和路由的关系。 构建路由关系,我们通常定义在router/index.js文件

映射关系主要有两个部分. 一个是path:路由的路径; 一个是component:关联的组件

在router/index.js文件中首先引入上面定义好的组件

import Home from '../components/Home';
import About from "../components/About";

然后指定路由路径和组件

const routes = [
{
path: "/home",
component: Home
},{
path: "/about",
component: About
}
]
  • 第三步: 使用路由, 通过<router-link>和<router-view>来展示组件

    现在组件有了, 路有关系也有了。 那么接下来就是要有个入口来展示组件或者路由了。 我们的入口只有一个, 那就是App.vue, 所以, 我们直接在这里定义两个入口即可。
<template>
<div id="app">
<!-- 定义两个路由链接 -->
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link> <!-- 展示组件内容 -->
<router-view></router-view>
</div>
</template>

<router-link>: 是一个vue-router中内置的组件, 它会被渲染成一个a标签。

<router-vie>: 会根据当前的路径, 动态渲染组件的内容

网页的其他内容, 例如:顶部的标题/导航,底部的版权信息等和/处于一个等级

在切换路由时, 切换的是挂在组建的内容, 其他不会发生改变

整体效果如下:

4. 路由的默认配置

现在我们进入首页显示的只有导航信息, 在页面必须点击某一个按钮,才能渲染出对应组件的内容。通常我们会有一个默认组件的展示。 否则首页内容就是空的了。如何设置默认展示的路由呢?

在路由表中增加一个重定向路由

{
path:"/",
redirect: "/home"
}

这样, 打开首页,直接加载home组件的内容

5. 修改静态路由的模式为history

我们之前都是采用hash的方式来静态路由跳转的, 但hash方式有一个缺点, 即带有#

例如:我们跳转都Home页, 他的路径是

http://localhost:8080/#/home

带有一个#, 这不符合我们通常路径的使用方法,所以,我们可以考虑将其替换为history的模式。 如何替换呢? 在router/index.js文件中

const router = new Router({
// 这里配置的是路由和组件的映射关系, 是一个数组.
routes,
mode: "history"
})

6. vue-link属性设置

1. to属性

我们在首页, 定义vue-link跳转的路由使用的就是to属性

<template>
<div id="app">
<!-- 定义两个路由链接 -->
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link> <!-- 展示组件内容 -->
<router-view></router-view>
</div>
</template>

2. tag属性

<router-link> 默认会被渲染成a标签, 如果我们想要将其渲染为其他标签是否可以呢? 当然是可以的, 使用tag属性, 比如: 我们想要将其渲染为button标签

<template>
<div id="app">
<!-- 定义两个路由链接 -->
<router-link to="/home" tag="button">首页</router-link>
<router-link to="/about" tag="button">关于</router-link> <!-- 展示组件内容 -->
<router-view></router-view>
</div>
</template>

3. replace属性

如下图, 我们在点击导航以后, 可以在浏览器向前或向后导航

如果我们不想要浏览器记录我们的请求行为, 可以使用replace. 我们只需要在<router-link>标签中增加属性replace就可以了. 这个属性不需要设置值

<template>
<div id="app">
<!-- 定义两个路由链接 -->
<router-link to="/home" tag="button" replace>首页</router-link>
<router-link to="/about" tag="button" replace>关于</router-link> <!-- 展示组件内容 -->
<router-view></router-view>
</div>
</template>

效果如下: 浏览器的返回和前进按钮都不可用

4. active-class 修改激活时样式名称的默认值

先来看看如何设置<router-link>元素的样式.

在点击按钮的时候, 在控制台可以看到有一个样式router-link-active, 这个样式是控制按钮激活的样式, 如果我们想要修改激活的效果, 修改这个样式即可.

比如: 我们设置按钮激活时字体颜色为红色.

<template>
<div id="app">
<!-- 定义两个路由链接 -->
<router-link to="/home" tag="button" replace>首页</router-link>
<router-link to="/about" tag="button" replace>关于</router-link> <!-- 展示组件内容 -->
<router-view></router-view>
</div>
</template> <script>
export default {
name: 'App'
}
</script> <style>
.router-link-active {
color:red;
}
</style>

重点看style里面的样式定义. 效果如下:

router-link-active是vue-router默认/激活时显示的样式, 如果想要修改这个样式名称, 可以使用active-class.

<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-view></router-view>
</div>
</template>

如上, 可以看到active-class="active", 表示将默认的属性重命名为active.

后面重定义样式的时候, 使用active即可

<style>
.active {
color:red;
}
</style>

全局修改active-clas的默认名称. 可以在路由里实现.

修改router/index.js文件

const router = new Router({
// 这里配置的是路由和组件的映射关系, 是一个数组.
routes,
mode: "history",
linkActiveClass: "active"
})

7. 通过代码跳转路由

上面我们都是在vue中直接使用<router-link>来路由, 我们还可以使用普通标签路由, 例如button标签, 来看看怎么实现

第一步: 定义两个button元素

<template>
<div id="app">
<!-- 定义两个路由链接 -->
<button @click="clickHome">首页</button>
<button @click="clickAbout">关于</button>
<!-- 展示组件内容 -->
<router-view></router-view>
</div>
</template>

这就是两个普通的button, 然后定义了两个click点击事件, 下面我们就要在点击事件中实现路由

第二步: 定义click事件, 路由到组件

<script>
export default {
name: 'App',
methods:{
clickHome() {
this.$router.push("/home")
console.log("点击home按钮")
},
clickAbout() {
this.$router.push("/about")
console.log("点击about按钮")
}
}
}
</script>

这里定义了点击事件. 通过this.$router.push("/home")来路由到home组件.

this.$router.push("/home"): 在每一个vue对象中, 通过this都可找到$router属性, 这是一个全局的属性.

this.$router.push("/home")是使用history的的方式路由到对应的组件, 可以通过浏览器的前进和后退按钮路由.

this.$router.replace("/home"): 不可以使用浏览器的前进和后退按钮路由.

8. 动态路由的使用

动态路由是什么概念呢? 通常我们的url是不变的, 比如. /home, 有些url是变化的,比如/user/zhangsan, /user/lisi, 对于变化的url, 我们如何路由呢?

下面就以用户为例, 来实现动态路由

第一步: 创建一个User.vue模板

<template>
<div>
<h2>用户界面</h2>
<div>欢迎你来到用户界面</div>
</div>
</template> <script>
export default {
name: "User"
}
</script> <style scoped>
</style>

第二步: 添加路由映射关系

import User from "../components/User"

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

这里path使用了:userId占位, 表示这里是一个占位符, 将被真实的userId替换. 后面在路由传递的时候变量需要和这里保持一致.

第三步: 使用user路由

当我们动态路由到user的时候, 需要使用变量userId, 我们可以在data中定义一个变量

<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 v-bind:to="'/user/'+userId" tag="button" replace active-class="active">用户</router-link> <router-view></router-view>
</div>
</template> <script>
export default {
name: 'App',
data(){
return {
userId:"zhangsan"
}
}
}
</script>

在上面使用了v-bind:to="'/user/'+userId"路由到/user/:userId, 而userId是我们在组件中定义的一个变量.

第三步:来看看效果

我们看到当点击用户的时候, 浏览器的url路径变为了/user/zhangsan.

第四步: 将参数传递到组件

我们希望在user组件中显示, 欢迎{{用户名}}来到用户页面, 如何实现呢?

要想实现这个效果, 需要使用到this.$route对象. 这是获取路由信息的对象.

<template>
<div>
<h2>用户界面</h2>
<div>欢迎{{userId}},来到用户界面</div>
</div>
</template> <script>
export default {
name: "User",
data(){
return {
userId:this.$route.params.userId
}
}
}
</script> <style scoped>
</style>

可以看到在data属性中,我们通过this.$route.params.userId 获取到了路由连接中的userId参数.

然后在页面通过语法糖的方式展示出用户{{userId}}即可.

来看看效果:

如上图所示, 我们看到userId变量被传递到了组件里面.

这里重点想要说的就是通过this.$route.params获取变量.

我们也可以在页面直接使用{{$route.params.userId}}获取路由参数

<template>
<div>
<h2>用户界面</h2>
<div>欢迎{{userId}},来到用户界面</div>
<div>{{$route.params.userId}}</div>
</div>
</template>

9. 认识路由的懒加载

首先为什么需要懒加载, 原因是, 当我们打包的时候, 会将所有的js文件,css进行打包, 打包到一个文件中, 然后在index.html页面中引入这些js,css文件.我们来看一下效果

首先, 我们先将项目打包, 然后看看打包后的文件结构

npm run build

打包完成以后, 会生成一个dist的文件夹,里面就是打包后的文件

如上图文件结构如下:

有一个index.html文件和static文件夹

  • index.html: 项目的主页面入口
  • static文件夹: 存放的是css和js等静态资源
    • css文件夹: 里面只有一个app.*.css文件, 这个文件是将所有的css整合到这里了
    • js文件夹: 该文件夹中有三个文件
      • app.*.js: 这个文件整合的是我们自己写的业务逻辑相关的js代码
      • manifest.*.js: 这个文件整合的是支撑我们的业务逻辑的底层支撑js代码
      • vendor.*.js: 这个文件整合了使用到的所有外部组件的js代码

一个项目可能有很多组件, 有自定义的组件, 有引入的外部组件, 那就会有很多js, css代码, 最终全部通过index.html加载进来, 这样在首次加载的时候速度就会很慢. 所以, 我们需要使用懒加载, 来提高首次加载速度.

什么是懒加载呢?

使用时才加载, 就是懒加载, 而不是一次性全部加载进来

怎样才能做到懒加载呢?

把不同的路由对应的组件分隔成不同的代码块, 而不是统一全部加载到app.*.js文件中,当路由被访问的时候才加载对应的js文件, 这样会更加高效

如何实现懒加载呢?

在路由定义的时候, 是有懒加载的方式

原来定义路由是这样的

import Home from '../components/Home';
import About from "../components/About";
import User from "../components/User" /*
* 第一步: 安装插件
* vue-router是一个插件, 所以, 我们需要使用vue.use(插件名) 来安装插件
*/
Vue.use(Router) /*
* 第二步: 构建VueRouter对象
* 在VueRouter中主要是配置路由和组件之间的映射关系的.
*/
const routes = [
{
path:"/",
redirect: "/home"
}, {
path: "/home",
component: Home
},{
path: "/about",
component: About
},{
path: "/user/:userId",
component: User
}
]

懒加载需要使用一个匿名函数来import, 表示使用的时候在import引入. 一个懒加载在打包的时候会单独打包成一个js文件.

// 这里会引入你要导入的组件, 然后通过路由配置组件内容
const Home = () =>import('../components/Home');
const About = () => import('../components/About');
const User = () => import('../components/User'); /*
* 第一步: 安装插件
* vue-router是一个插件, 所以, 我们需要使用vue.use(插件名) 来安装插件
*/
Vue.use(Router) /*
* 第二步: 构建VueRouter对象
* 在VueRouter中主要是配置路由和组件之间的映射关系的.
*/
const routes = [
{
path:"/",
redirect: "/home"
}, {
path: "/home",
component: Home
},{
path: "/about",
component: About
},{
path: "/user/:userId",
component: User
}
]

我们将代码的引入方式改变了,这样在打包的时候, 会将每一个import进来的文件打包成一个单独的js文件. 如下图所示:

和之前相比, 多了3个文件, 因为使用了三个懒加载组件.

二. vue-router的嵌套

嵌套路由是一个很常见的功能, 比如主业引入了组件Home, 我们在Home里面引入了banner图组件. 这样就是组件的嵌套.

我们的路由映射规则是: 一个路径映射一个组件. 访问两个路径, 会分别渲染两个组件.

下面来实现嵌套路由,

第一步: 创建组件,创建两个组件

HomeBanner.vue组件

<template>
<div>
<h2>首页banner图</h2>
<ul>
<li>banner图1</li>
<li>banner图2</li>
<li>banner图3</li>
<li>banner图4</li>
</ul>
</div>
</template> <script>
export default {
name: "HomeBanner"
}
</script> <style scoped> </style>

HomeNews.vue组件

<template>
<div>
<h2>首页新闻</h2>
<ul>
<li>第一条新闻</li>
<li>第二条新闻</li>
<li>第三条新闻</li>
<li>第四条新闻</li>
</ul>
</div>
</template> <script>
export default {
name: "HomeNews"
}
</script> <style scoped> </style>

第二步: 创建组件路由

我们要在Home也添加子路由, 需要在路由里面增加一个children属性配置.

//引入子路由-使用懒加载的方式进行加载
const HomeBanner = ()=>import('../components/HomeBanner');
const HomeNews = () => import('../components/HomeNews'); {
path: "/home",
component: Home,
children: [{
path:'',
redirect: 'HomeNew'
},{
path: 'HomeNew', //注意: 这里面没有/
component: HomeNews
},{
path: 'HomeBanner',
component: HomeBanner
}]
}

里面的路径依然是有两个部分:

  • 一个是path路由路径: 这里需要注意的是,不需要在路径名的前面加/
  • 另一个是component: 指定组件名称

第三步: 增加<router-link> 和 <router-view/>

我们要在Home页面展示子组件, 因此需要将子组件的展示放在页面上

<template>
<div>
<h2>这是Home主页</h2>
<div>欢迎来到home主页</div>
<router-link to="/home/homeNew">新闻</router-link>
<router-link to="/home/homeBanner">Banner图</router-link>
<router-view></router-view> </div>
</template>

完成以后,效果如下:

三. vue-router参数传递

vue-router参数传递有两种方式: 第一种是: param的方式. 第二种是: query的方式

1. param方式

这种方式在动态路由的时候有提到过. 下面来回顾一下:

第一步: 创建一个User.vue组件

<template>
<div>
<h2>用户界面</h2>
</div>
</template> <script>
export default {
name: "User",
}
</script> <style scoped>
</style>

第二步:创建动态路由的时候, 定义变量

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

我们定义了一个user/:userId, 这样的动态路由. 路由可以是/user/zhangsan, 或者/user/lisi

第三步: 在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 v-bind:to="'/user/' + userId" tag="button" replace active-class="active">用户</router-link> <!-- 展示组件内容 -->
<router-view></router-view>
</div>
</template> <script>
export default {
name: 'App',
data(){
return {
userId:"zhangsan"
}
}
}
</script>
<style>
.active {
color:red;
}
</style>

这里面userId是变化的部分. 通过bind事件动态将userId绑定到path路径中

<router-link v-bind:to="'/user/' + userId" tag="button" replace active-class="active">用户</router-link>

第四步: 修改User.vue组件

首先, 在User.vue脚本中获取传递过来的路由参数. 我们使用[this.$route.params.变量名]的方式获取路径参数

<script>
export default {
name: "User",
data() {
return {
userId: this.$route.params.userId
}
}
}
</script>

然后使用语法糖, 将变量显示出来

<template>
<div>
<h2>用户界面</h2>
<div>欢迎{{userId}},来到用户界面</div>
<div>{{$route.params.userId}}</div>
</div>
</template>

也可以直接使用使用{{$route.params.userId}}的写法

以上是使用参数的方式传递变量.

2. query方式

第一步: 配置路由的时候是普通配置: /user

第二步:传递的方式使用query的方式, query是一个对象,

第三步:传递后形成的路径是:/user?useId=2, /user?userId=9

下面来举个案例:

第一步: 创建一个组件Profile.vue

<template>
<div>
<h2>这是一个Profile组件</h2>
</div>
</template> <script>
export default {
name: "Profile"
}
</script> <style scoped> </style>

第二步: 配置路由

// 配置路由相关的信息
// 导入vue和vue-router
import Vue from 'vue'
import Router from "vue-router";
// 这里会引入你要导入的组件, 然后通过路由配置组件内容
// 懒加载
const Profile = () => import('../components/Profile') /*
* 第一步: 安装插件
* vue-router是一个插件, 所以, 我们需要使用vue.use(插件名) 来安装插件
*/
Vue.use(Router) /*
* 第二步: 构建VueRouter对象
* 在VueRouter中主要是配置路由和组件之间的映射关系的.
*/
const routes = [
{
path: "/profile",
component: Profile
}
]
const router = new Router({
// 这里配置的是路由和组件的映射关系, 是一个数组.
routes,
mode: "history",
linkActiveClass: "active"
}) /*
* 第三步: 将VueRouter对象导出
*
*/
export default router

第三步: 渲染组件

 <!-- 配置动态路由 -->
<router-link v-bind:to="{path:'/profile', query:{name:'lily',sex:'男',age:12}}" tag="button" replace active-class="active">档案</router-link>

通常我们定义路由是这样定义的

 <!-- 配置动态路由 -->
<router-link to="/profile" tag="button" replace active-class="active">档案</router-link>

但是, 这样路由就固定写死了, 所以肯定不行, 我们需要给他一个变量, 使用v-bind:to

然后就有了下面这个写法

v-bind:to="{path:'/profile', query:{name:'lily',sex:'男',age:12}}"

第四步: 来看一下效果

我们看到路径上带了?参数.

http://localhost:8080/profile?name=lily&sex=%E7%94%B7&age=12

第五步: 在Profile组件中获取参数

获取参数有两种方式

  1. 直接语法糖方式获取{{$route.query.***}}
  2. 在脚本中获取:this.$route.query.***

如下采用方式一获取参数:

<template>
<div>
<h2>这是一个Profile组件</h2>
<h4>{{$route.query}}</h4>
<h4>{{$route.query.name}}</h4>
<h4>{{$route.query.age}}</h4>
<h4>{{$route.query.sex}}</h4>
</div>
</template>

第六步: 查看效果

四. vue-router导航守卫

导航守卫, 听者特别的高大上. 到底是什么意思呢?

在之前的html页面, 如果我们想要实现title跟着页面变, 那么只需要设置html页面的title属性就可以了.

在vue中, 只有一个index.html页面,如何实现title的改变呢?

有两种方法:

  • 第一种, 使用生命周期函数created().
  • 第二种: 使用全局导航守卫

1. 使用生命周期实现页面更新title属性

组件的生命周期, 这在之前有提到过. 子组件的生命周期中有很多函数, 比如created(), mouted(), updated(), 我们可以在他的生命周期增加处理逻辑.

,我们可以在created()方法中增加处理逻辑.

<template>
<div>
<h2>这是Home主页</h2>
<div>欢迎来到home主页</div>
<router-link to="/home/homeNew">新闻</router-link>
<router-link to="/home/homeBanner">Banner图</router-link>
<router-view></router-view> </div>
</template> <script>
export default {
name: "Home",
created() {
document.title="首页"
}
}
</script> <style scoped>
</style>

我们看到在script中增加一个created方法. 并指定了title名称.

<script>
export default {
name: "Home",
created() {
document.title="首页"
}
}
</script>

来看一下效果

这样有什么问题? 假如现在有100个页面, 我们需要在100个页面中都增加created()函数. 虽然可以实现功能,但似乎有些麻烦, 有没有可以统一修改的办法呢?我们可以使用全局导航守卫实现

3.2. 使用全局导航守卫的方式更新title属性

什么是导航守卫?

来看看官网的解释: https://router.vuejs.org/zh/guide/advanced/navigation-guards.html

正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。

  • 这里的导航,指的就是路由的跳转或者取消跳转
  • 守卫指的是: 有很多钩子方法, 允许我们在某一个过程中植入代码逻辑.
  • 常见的导航守卫有: 全局导航守卫(包括三个: 全局前置守卫, 全局解析守卫, 全局后置守卫), 路由独享导航守卫, 组件内的守卫.

下面老看看[全局前置守卫]

1. 使用 router.beforeEach 注册一个全局前置守卫

const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})

当一个导航触发时,全局前置守卫按照创建顺序调用。

守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。

我们来看看router.beforeEach的实现.

点击beforeEach进入到router.ts文件, 可以看到里面定义了router.beforeEach()方法的定义

beforeEach(guard: NavigationGuard): Function

这是一个函数, 方法有一个入参, 参数是一个方法, 参数名是guard. 方法体是NavigationGuard. 我们来看看NavigationGuard的实现逻辑

export type NavigationGuard<V extends Vue = Vue> = (
to: Route,
from: Route,
next: NavigationGuardNext<V>
) => any

NavigationGuard也是一个函数, 并且这个函数继承自Vue. 函数有三个入参: to, from, next. 方法实现是any.

所以,我们要想重写beforeEach()方法. 那么参数就要定一个方法, 并且方法里有三个入参. 方法如下:

router.beforeEach(function(to, from, next) {

})

除了这种方法, 我们还可以使用箭头函数

router.beforeEach((to, from, next) =>{

})

两种都是可以的.

接下来, 看看函数中三个参数都是什么含义呢?

  • to: 是一个router对象, 含义是导航到的目标路径.
  • from: 是一个router对象, 含义是当前导航正要离开的路由.
  • next: 是一个函数, 这是一个钩子函数. 一定要调用该方法来 resolve 这个钩子

函数实现的部分, 一定要调用next()方法. 表示导航继续向下执行. 如果不调用next(), 那么后面的函数将不会被解析或者执行.

也就是说, 代码这至少是这样的

router.beforeEach((to, from, next) =>{
next();
})

确保 next 函数在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错。

2. 在路由index.js文件中增加元数据属性, 并设置title属性值

const routes = [
{
path:"/",
redirect: "/home",
}, {
path: "/home",
component: Home,
children: [{
path:'',
redirect: 'HomeNew'
},{
path: 'homeNew', //注意: 这里面没有/
component: HomeNews
},{
path: 'homeBanner',
component: HomeBanner
}],
meta: {
title: "首页"
}
},{
path: "/about",
component: About,
meta: {
title: "关于"
}
},{
path: "/user/:userId",
component: User,
meta: {
title: "用户"
}
},{
path: "/profile",
component: Profile,
meta: {
title: "档案"
}
}
]

增加的元数据内容如下

    meta: {
title: "档案"
}

3. 后面在全局导航路由中设置title属性

router.beforeEach((to, from, next) => {
console.log(to)
console.log(from)
document.title = to.matched[0].meta.title
next()
})

我们通过打印to和from对象, 发现他们确实都是路由对象, 我们可以通过matched中的第0个元素,获取到meta中的内容.

我们看到其实to下面和matched平级的也有一个meta属性, 但是这个属性在某些情况下值是空的. 所以, 我们还通过matched的第一个元素来获取meta对象

以上就是全局前置导航守卫的用户, 后置导航守卫等其他守卫, 用法与其相似, 可以查看官方文档: https://router.vuejs.org/zh/guide/advanced/navigation-guards.html

前置守卫也好, 后置守卫也好, 都是路由组件的钩子函数, 通过钩子函数, 我们可以在对应的生命周期织入业务逻辑.

理解守卫的含义

全局前置守卫, 全局解析守卫, 全局后置守卫: 定义在路由文件中, 表示对所有路由都有效

路由独享守卫: 可以在路由配置上直接定义 beforeEnter 守卫:

组件内的守卫:你可以在路由组件内直接定义以下路由导航守卫, 有效范围是某个组件.

                       常见的组件内守卫: beforeRouteEnter(进入路由前),beforeRouteUpdate (更新路由前)),beforeRouteLeave(离开路有前)

五. keep-alive

我们有首页, 关于, 用户, 档案. 首页下面有两个按钮[新闻],[消息]

当点击首页的[消息], 然后切换到关于页面, 再回到首页的时候, 我们希望能够继续展示[消息]的内容

默认是不会保留操作的记忆的. 下次回来直接到[首页->新闻], 使用keep-alive就可以有保留记忆的效果了

为什么每次回到首页, 都会展示[首页->新闻]的内容呢?

原因是每次回到首页都会创建一个新的Home组件.

我们来验证每次回到首页都会重新创建一个新的组件. 来看看vue组件的生命周期. 其实Vue对象本身也是一个大组件

如上图所示:在vue整个生命周期, 他有很多挂载函数, 比如:beforeCreate(创建组件之前), created(创建组件后), beforeMount(挂载组件之前), mounted(挂载组件之后),

beforeUpdate(组件值更新之前),updatd(组件值更新之后),beforeDestroy(组件销毁之前),destroyed(组件销毁之后)

1. 验证, 是否销毁了原来的组件呢?

我们只需要验证created()和destroyed()两个函数是否每次跳走都会被执行一遍.

<script>
export default {
name: "Home",
created() {
document.title="首页"
console.log("created home")
},
destroyed() {
console.log("destroyed home")
}
}
</script>

如上所示:定义了创建函数和销毁函数, 下面来看看当跳走的时候, 是不是会执行这两个函数.

如上图所示: 当离开首页,就会执行destroyed函数, 当进入首页, 就会执行created函数. 说明每次确实都在创建新的组件

2. 如何才能让组件有记忆,而不是每次都重新创建呢?

如果想要实现路由跳转走以后, 返回来不需要重新创建组件, 我们可以使用keep-alive, 他的用法很简单

在组建展示的位置增加标签

    <keep-alive>
<router-view></router-view>
</keep-alive>

这样调走再跳回来就不会重新创建组建了, 来看看效果

我们看到只有第一次创建了home组件, 后来路由调走, 组件并没有被销毁.

3.案例: 实现从[首页->banner图]跳走后, 在跳回来, 依然定位在[首页->banner图]的位置

跳走, 在跳回来, 这实际上是在控制路由.我们可以让路由调走之前记住当前组件的路由. 要想实现这个功能,需要了解一下几个钩子函数:

  1. activated: 路由激活时触发
  2. deactivated: 路由取消激活时触发

先来看这两个: 这两个函数生效的条件是 : 设置了<keep-alive>组件才有效. 也就是说, 组件离开时不销毁.

我们在home组件中增加两个方法

    activated() {
// 路由激活
console.log("activated home")
},
deactivated() {
// 路由取消激活
console.log("deactivated home")
},

然后来看看效果: 我们发现跳到home路由, 触发activated方法, 离开home路由, 触发deactivated方法.

如何记住路由呢? 我们可以定义一个变量来记住调走前的路由.

this.$route.path : 他是获取当前激活的路由

要想实现这个功能, 还需要使用到路由守卫.

路由守卫有三种类型

const Foo = {
template: `...`,
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}

我们选择使用最后一个beforeRouteLeave, 在离开当前路由的时候, 记录下离开前的路由.

代码实现如下:

1. 在home组件增加两个方法, 一个是activated组件激活的时候重定向路由, 另一个是beforeRouteLeave组件离开前记录离开前的路由

activated() {
// 路由激活, 路由到path路径
this.$router.push(this.path)
},
beforeRouteLeave(to, from, next) {
console.log("离开home前的路径 "+this.path)
this.path = this.$route.path;
next()
}

2. 看一下运行的效果:

以上就是keep-alive的内容, 这里重要要有一个概念, 组件调走以后是会销毁原来的组件的.如果我们不想它被销毁, 那么可以使用<keep-alive>组件实现.

4. keep-alive 的属性

keep-alive有两个属性: 一个是include, 另一个是exclude

  • include: 字符串或者正则表达式, 只有匹配的组件才会被缓存
  • exclude: 字符串或者正则表达式, 匹配到的组件不会被缓存.

比如,我们整个组件都希望每次加载会缓存, 但是档案组件特殊, 希望他每次都被销毁, 重新创建.

第一步: 在Profile组件中增加created和destroy事件

created() {
console.log("Profile created")
},
destroyed() {
console.log("Profile destroyed")
}

第二步: 在<keep-alive>中配置排除Profile组件

<keep-alive exclude="Profile">
<router-view></router-view>
</keep-alive>

这样, Profile组件就不会被缓存了

第三步: 演示效果

17. vue-route详细介绍的更多相关文章

  1. Java 集合系列17之 TreeSet详细介绍(源码解析)和使用示例

    概要 这一章,我们对TreeSet进行学习.我们先对TreeSet有个整体认识,然后再学习它的源码,最后再通过实例来学会使用TreeSet.内容包括:第1部分 TreeSet介绍第2部分 TreeSe ...

  2. vue对比其他框架详细介绍

    vue对比其他框架详细介绍 对比其他框架 — Vue.jshttps://cn.vuejs.org/v2/guide/comparison.html React React 和 Vue 有许多相似之处 ...

  3. kvm详细介绍

    KVM详解,太详细太深入了,经典 2016-07-18 19:56:38 分类: 虚拟化 原文地址:KVM详解,太详细太深入了,经典 作者:zzjlzx KVM 介绍(1):简介及安装 http:// ...

  4. Vue框架的介绍及使用

    Vue框架 定义:渐进式 JavaScript 框架 渐进式:可以控制一个页面的一个标签,可以控制一系列标签,也可以控制整个页面,甚至可以控制整个前台项目. 通过对框架的了解与运用程度,来决定其在整个 ...

  5. Vue路由-详细总结

    Vue路由vue-router   前面的话 在Web开发中,路由是指根据URL分配到对应的处理程序.对于大多数单页面应用,都推荐使用官方支持的vue-router.Vue-router通过管理URL ...

  6. [No0000A7]批处理经常用到的变量及批处理>NUL详细介绍

    绝对路径是指调用绝对的程序位置的路径,例如: start C:\Windows\test.exe 相对路径是文件改变路径以后还会按照变量的路径所在位置去调用,例如: start %WINDIR%\te ...

  7. linux配置网卡IP地址命令详细介绍及一些常用网络配置命令

    linux配置网卡IP地址命令详细介绍及一些常用网络配置命令2010-- 个评论 收藏 我要投稿 Linux命令行下配置IP地址不像图形界面下那么方 便,完全需要我们手动配置,下面就给大家介绍几种配置 ...

  8. web.xml 详细介绍(转)

    web.xml 详细介绍 1.启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取<listener>和<context-param>两个结点. 2.紧 ...

  9. linux awk 内置函数详细介绍(实例)

    这节详细介绍awk内置函数,主要分以下3种类似:算数函数.字符串函数.其它一般函数.时间函数 一.算术函数: 以下算术函数执行与 C 语言中名称相同的子例程相同的操作: 函数名 说明 atan2( y ...

  10. Ubuntu根目录下各文件夹的功能详细介绍

    Ubuntu的根目录下存在着很多的文件夹,但你知道他们都存放着哪些文件呢?这些是深入了解Ubuntu系统必不缺少的知识,本文就关于此做一下介绍吧. /bin/    用以存储二进制可执行命令文件. / ...

随机推荐

  1. css 命名冲突 & solution

    css 命名冲突 & solution 类似这样,为了解决模块间可能存在的 css 命名冲突问题,需要单独提供给模块开发者一套模块开发环境:同时,文档上要有如何使用的规范说明. CSS 建议: ...

  2. js & Event Bus

    js & Event Bus global event handler (broadcast / trigger / emit / listen ) // 实现一个 EventBus类,这个类 ...

  3. calendar merge date

    calendar merge date componentDidMount () { const { monthDays, // monthDates, } = this.props; const d ...

  4. Spring学习过程中遇到的No bean named 'beanId' is defined报错

    ApplicationContext applicationContext= new ClassPathXmlApplicationContext("bean.xml");Obje ...

  5. NDB程序进近复飞保护区的绘制

    终于有点空闲,找张图来演练一下<风螺旋标准模板>软件的用法. 某机场NDB进近程序剖面图如下图所示: 该机场采用了近台和远台的双台布局,近台和远台均为NDB与指点标的合装台,没有中间进近定 ...

  6. 如何用JavaDoc命令生成帮助文档

    如何用JavaDoc命令生成帮助文档 文档注释 在代码中使用文档注释的方法 /** *@author *@version * */ 生成帮助文档 打开java文件所在位置,在路径前加入cmd (注意有 ...

  7. MySQL 常用命令手册 增删改查大法

    一.数据库操作 创建数据库 语法: CREATE DATABASE database_name; 删除数据库 删除数据库务必谨慎!因为执行删除命令后,所有数据将消失. 语法: DROP DATABAS ...

  8. 音视频+ffmpeg

    雷霄骅:https://me.csdn.net/leixiaohua1020 致敬! 1.[总结]视音频编解码技术零基础学习方法 https://blog.csdn.net/leixiaohua102 ...

  9. DNS Rebinding漏洞原理

    目录 SSRF过滤器设计 背景知识 DNS TTL 公网DNS服务器 DNS重绑定 自建DNS服务器 利用步骤图解 实战中的注意事项 防御 参考 DNS Rebinding 广泛用于绕过同源策略.SS ...

  10. 基于CameraLink的逻辑综合和版图设计

    前期接口设计用的是Vivado18.3+Modelsim10.6,逻辑综合及版图生成的环境是Ubuntu16,逻辑综合用的工具Design Compiler,生成版图用的工具是Encounter. 下 ...