一口气拿下vue-router所有知识点,薪资暴涨3000
Posted 前端呆头鹅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一口气拿下vue-router所有知识点,薪资暴涨3000相关的知识,希望对你有一定的参考价值。
一口气拿下vue-router所有知识点,薪资暴涨3000
- 一 vue路由基础使用【固定路由的配置和使用】
- 二 如何在路由中携带参数【动态路由的配置和使用】
- 三 如何提取页面相同内容【嵌套路由的配置和使用】
- 四 路由的两种模式有什么不同【hash和history的区别】
- 五 history模式的使用和问题
- 六 浅析vue-router实现原理【面试必备】
- 七 怎样实现自己的vue-router
一 vue路由基础使用【固定路由的配置和使用】
首先我们展示一下router使用后的效果。
首先启动服务后,输入路由http://localhost:8080/#/A
,到达页面A,展示页面A内容,点击页面上按钮或者将url切换为http://localhost:8080/#/B
,到达页面B,展示页面B内容。
怎样配置
- 创建两个文件src/views/a.vue和src/views/b.vue,用来展示路由切换效果。
// src/views/a.vue
<template>
<div>
<h1>我是页面a</h1>
</div>
</template>
// src/views/b.vue
<template>
<div>
<h1>我是页面b</h1>
</div>
</template>
- 创建src/router/index.js文件,在src/router/index.js中引入router必要文件,导出router对象。
src/router/index.js文件代码示例如下。
import Vue from "vue";
import VueRouter from "vue-router";
import a from "../views/a.vue";
import b from "../views/b.vue";
// 注册路由插件
Vue.use(VueRouter);
// 定义路由规则
const routes = [
path: "/B",
name: "A",
component: a,
,
path: "/B",
name: "B",
component: b,
,
];
// 创建router对象
const router = new VueRouter(
routes,
);
export default router;
- 在src/main.js中,在全局vue实例创建的时候,注入router对象。
src/main.js代码示例如下。
...
import router from "./router";
...
new Vue(
router,
...
render: (h) => h(App)
).$mount("#app");
这一步做了什么呢,我们可以将vue实例打印出来,看一下router写入前后,vue实例有什么变化。
// src/main.js
const vm1 = new Vue(
router,
// store,
render: (h) => h(App),
).$mount("#app");
const vm2 = new Vue(
// router,
// store,
render: (h) => h(App),
).$mount("#app");
console.log(vm1, vm2);
我们写了两个不同的Vue实例,两者唯一的区别是有无注入router,将它们打印出来后对比一下,可以看到,注入router的vue实例中增加了几个router相关的属性,
r
o
u
t
e
r
和
router和
router和route属性被赋值。
点击打开后可以看到, r o u t e r 中 有 一 些 路 由 相 关 的 方 法 , router中有一些路由相关的方法, router中有一些路由相关的方法,route中有当前路由的信息。
这些信息已经挂载到了全局vue实例上,在页面中就可以直接使用了。
- 在App.vue中对应位置添加
<router-view/>
标签,该标签为路由组件的占位符,路由切换时,该标签会被替换成对应的路由组件。就达到了我们想要的效果。
在切换路由时,我们可以通过点击<router-link />
标签或者手动更改url的方式进行页面切换,下面是一个带有<router-view/>
标签和<router-link />
标签的代码示例。
这里我们为router-link标签写上了一些样式,使展示更加美观。
<template>
<div id="app">
<router-link class="a" to='A'>跳往页面A</router-link>
<router-link class="b" to='B'>跳往页面B</router-link>
<router-view />
</div>
</template>
<style>
.a,.b
border: 1px solid #42b983;
padding: 5px 10px;
margin: 5px;
margin-top: 300px;
color: #42b983;
</style>
怎样控制路由跳转
刚刚介绍了路由在html中使用标签进行跳转,但有时我们希望在js中跳转,该怎样操作呢?这就用到上面挂载在vue实例上的$router。代码示例如下。
this.$router.push('/b') // 根据路由文件中的path跳转到页面B
this.$route.query // 取得当前路由的参数
this.$router.push( name: 'B' ) // 根据路由文件中的name跳转到页面b
this.$router.replace('/b') // 在不记录当前的路由的情况下跳转到页面b,无法从b后退到当前路由
this.$router.go(-2) // 后退到历史某次访问的页面
this.$router.go(-1) === this.$router.back()
二 如何在路由中携带参数【动态路由的配置和使用】
刚才我们对于不同页面配置了不同固定路由。
不知你有没有注意到csdn的个人主页,小明的个人主页链接为https://blog.csdn.net/123
,而小米的个人主页链接为https://blog.csdn.net/456
,相同的页面对应的路由却不一样,似乎路由中携带了一个参数,用来区分不同用户,而路由指向的又是同一个页面,这是怎么回事呢?
怎样携带参数
我们再看上面配置的src/router/index.js文件route对象。
// src/router/index.js
const routes = [
path: "/a",
name: "A",
component: a,
,
path: "/b",
name: "B",
component: b,
,
];
这时我们希望将b页面的路由达到上面携带不同参数,有指向同一个页面的效果,我们将这种路由叫做动态路由,动态路由的配置也很简单,对应位置前加冒号就可以,代码示例如下。
// src/router/index.js
const routes = [
path: "/a",
name: "A",
component: a,
,
path: "/b/:id", // 这里变化了哦
name: "B",
component: b,
,
];
这时我们可以看到,原来的路由http://localhost:8080/#/b
已经访问不到该页面了,将路由变更为http://localhost:8080/#/b/1
可以正常访问页面,将b/后面更改为任意值都可以访问到页面。
带有参数的动态路由也可以通过js指定name跳转。
this.$router.push( name: 'B', params: id: 1 )
现在参数已经写入动态路由中了,怎么获取该参数呢?
怎样获取参数
- 使用 r o u t e . p a r a m s . i d 获 取 , 动 态 路 由 中 的 参 数 都 可 以 通 过 v u e 全 局 属 性 route.params.id获取,动态路由中的参数都可以通过vue全局属性 route.params.id获取,动态路由中的参数都可以通过vue全局属性route下的params对象获取,代码示例如下。
<template>
<div>
<h1>我是页面b</h1>
通过当前路由获取: $route.params.id
</div>
</template>
<script>
export default
name: B
;
</script>
- 使用props获取,使用该方法需要在route路由中配置props为true,代码示例如下。
// src/router/index.js
const routes = [
path: "/a",
name: "A",
component: a,
,
path: "/b/:id",
name: "B",
component: b,
props:true,
,
];
<template>
<div>
<h1>我是页面b</h1>
通过props获取: id
</div>
</template>
<script>
export default
name: B,
props: ["id"],
;
</script>
三 如何提取页面相同内容【嵌套路由的配置和使用】
刚刚我们在app.vue中写入了标签,该标签会被路由文件中配置的组件替换。
当前页面是这样的。
现在我们有了新的需求,在b页面中,我们希望可以再开辟一块自由区域,可以随着路由变化。
这时我们的b页面就是一个layout页面(布局页面),它里面包含一部分可以分化的内容,可以分化出不同页面。
具体到页面上,我们将实现下面的效果。
首先我们新建三个文件,将layout页面和内部的两个分化页面layoutA和layoutB准备好。
// src/view/LayoutA.vue
<template>
<div>AAAAAAAA</div>
</template>
// src/view/LayoutB.vue
<template>
<div>AAAAAAAA</div>
</template>
// src/component/Layout.vue
<template>
<div>
<div class="bar">header</div>
<div class="content">
<router-view />
</div>
<div class="bar">footer</div>
</div>
</template>
<style lang="scss" scoped>
.bar
width: 100px;
padding: 10px;
text-align: center;
background-color: green;
padding:20px 0;
color: #fff;
width: 100%;
.content
background-color: khaki;
height: 300px;
color: green;
line-height: 300px;
width: 100%;
font-size: 40px;
</style>
然后我们在src/router/index.js中修改router配置如下。
const routes = [
... ...
path: "/b",
name: "B",
component: layout,
children: [
name: "LayoutA",
path: "/b/a",
component: LayoutA,
,
name: "LayoutB",
path: "/b/b",
component: LayoutB,
,
],
,
];
当路由/b/a或者/b/b的时候,组件layout会替换app.vue中的标签,组件LayoutA或者LayoutB会替换组件layout中的标签。
就实现了上面的效果。
四 路由的两种模式有什么不同【hash和history的区别】
表现形式有什么区别
hash模式带有#号,#号后面的内容是我们的路由地址,history模式是正常的路由。
hash:http://localhost:8080/#/b
history:http://localhost:8080/b
实现原理有什么区别
hash模式:基于锚点也就是#号,当#后面的路由发生变化后,触发onhashchange事件,在事件中对页面进行操作。
history模式:基于h5中的historyAPI。
history.pushState() 在浏览器记录中添加一个新纪录,不向后端发送请求。
history.replaceState() 修改浏览器历史中当前历史记录,不向后端发送请求。
由于浏览器的url栏中始终显示最新的url记录,所以就好像触发了页面更新一样,其实并没有。
五 history模式的使用和问题
history模式配置和使用
history的配置很简单,在src/router/index.js中,创建路由实例时设置属性mode为history即可。
import Vue from "vue";
import VueRouter from "vue-router";
...
Vue.use(VueRouter);
const routes = [...];
const router = new VueRouter(
mode: "history", // 在这里设置
routes,
);
export default router;
现在我们再次访问刚才的页面。
现在使用http://localhost:8080/#/b/b
已经访问不到啦,我们将#去掉,url更改为http://localhost:8080/b/b
,页面出现了。
history浏览器请求问题
history模式中,在触发页面跳转时,我们使用history.pushState() 在浏览器记录中添加一个新纪录,不向后端发送请求。
但如果我们使用浏览器触发跳转会怎样呢,比如直接向浏览器中输入url后,或者点击页面刷新。
有的同学有讲,我在开发过程中经常直接使用浏览器跳转呀,没遇到问题,这是因为我们使用的vue脚手架已经帮我们解决了这个问题,但是当代码打包,上线后,问题就出现了,浏览器会告诉我们,找不到该页面。
这是因为我们使用代码去进行跳转/b/b,实际上不是真实的跳转,不会向服务端发送请求,而浏览器跳转会向后端发送请求,后端一看,没有/b/b这个请求路径呀,就会报错。
所以使用history模式,需要在服务端配置一下。
如果我们使用的是node做服务端时,可以通过配置中间件/插件(connect-history-api-fallback)来实现对history的支持。把这个插件在node.js服务端引入后注册就好了。
如果我们使用的是nginx服务,在nginx的配置文件中配置当找不到对应页面的时候返回首页就好啦。
因为我们主要是讲vue-router,这里就不展开讲解node服务和nginx服务啦。
六 浅析vue-router实现原理【面试必备】
hash模式实现原理
- url中#后面的内容作为路径地址
- 监听hashchange事件
- 根据当前路由地址找到对应组件重新渲染
history模式实现原理
- 通过history.pushState()方法改变地址栏
- 监听popstate事件
- 根据当前路由地址找到对应组件重新渲染
七 怎样实现自己的vue-router
vue-router是什么
vue-router是什么?实现vue-router从何下手,首先我们来分析它的使用,在src/router/index.js中,我们引入vue-router,使用vue.use()注册了它,又new了它的实例,最后导出。
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
const routes = [...];
const router = new VueRouter(
mode: "history",
routes,
);
export default router;
Vue.use方法里面的参数可以是一个对象或者一个函数,当它是一个函数的时候它会被执行,当它是一个对象的时候,会执行对象内部的install函数,那么vue-router是什么呢。
下面我们使用new创建了一个vue-router实例,这里可以看出,vue-router是一个类(类也是对象哦)。
我们现在对vue-router有了一定的认知,它是一个类,里面包含install方法,它有一个构造函数,可以对new时传入的参数进行处理。
知道了它是什么,我们就可以向着这个方向开发啦。
实现一个vue插件【install】
实现一个插件需要几步?首先我们写一个含有install方法的类。
export default class VueRouter
static install(Vue)
该类作为插件,被vue调用install方法的时候,会传入一个参数,就是vue构造函数。在install中我们可以保存vue构造函数和对vue构造函数做改动。
首先我们可以在install中对插件是否已安装做判断,已安装状态下直接返回。我们可以通过设置一个变量来记录。
然后将vue构造函数记录在一个变量中,以备使用。
let _Vue = null;
export default class VueRouter
static install(Vue)
// 判断当前插件是否被安装
if (VueRouter.install.installed)
return;
VueRouter.install.installed = true;
// 将vue构造函数记录到全局变量
_Vue = Vue;
最后对vue构造函数做一定的修改,我们刚才有提到,我们创建vue实例的时候,将返回的router传入了vue实例中。
new Vue(
router,
render: (h) => h(App),
).$mount("#app");
传入之后vue做了什么呢,要知道router对于vue来说只是一个插件而已,vue原本的逻辑是不包括对router的处理的,所以router处理的这一步应该是写在vue-router的install中的。
在创建vue实例前,vue会调用钩子函数beforeCreate,这部分逻辑可以使用混入/mixin写入。
let _Vue = null;
export default class VueRouter
static install(Vue)
...
// 把创建vue实例时候传入的router对象注入到vue实例上
_Vue.mixin(
beforeCreate()
if (this.$options.router)
_Vue.prototype.$router = this.$options.router;
,
);
我们使用混入,为vue实例的beforeCreate钩子函数添加了一段逻辑,这里的this.$options指的就是我们在创建vue实例时传入的对象。比如下面的代码中,option就是含有router和render属性的对象。
new Vue(
router,
render: (h) => h(App),
).$mount("#app");
还记得前面我们有将vue实例打印出来看吗,option中添加了router后,vue实例的$router就有值啦。
现在install函数就写好了,我们的vuerouter已经是一个合格的插件了,我们盘点一下一共做了几步。
- 判断当前插件是否被安装
- 将vue构造函数记录到全局变量
- 为vue添加beforeCreate逻辑,增加对router信息的处理。