vue-router是什么?
vue-router是什么,它是干什么的? 首先需要知道路由这个词,这里指的路由并不是指我们平时所说的生活中的硬件路由器,这里的路由就是SPA(单页应用)的路径管理器。vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。
那与传统的页面跳转有什么区别呢?
1.vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。
2.传统的页面应用,是用一些超链接来实现页面切换和跳转的。
在vue-router单页面应用中,切换路由实际上是组件的切换。路由模块的本质 就是建立起url和组件之间的映射关系。
至于为啥不能用a标签,这是因为用Vue做的都是单页应用,就相当于只有一个主的index.html页面,没有页面的实际切换,只是页面的显示控制。
vue-router实现原理
SPA(single page application):单一页面应用程序,有且只有一个完整的页面;当它在加载页面的时候,不会加载整个页面的内容,而只更新某个指定的容器中内容。
单页面应用(SPA)的核心之一是:
1.更新视图而不重新请求页面;
2.vue-router在实现单页面前端路由时,提供了三种方式:Hash模式、History模式、abstract模式,旧版根据mode参数来决定采用哪一种方式,新版则如下
路由模式
vue-router 提供了三种运行模式:
● hash: 使用 URL hash 值来作路由。默认模式。
● history: 依赖 HTML5 History API 和服务器配置。
● abstract: 支持所有 JavaScript 运行环境,如 Node.js 服务器端,不需要依赖浏览器的API。
Hash模式
vue-router 默认模式是 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,当 URL 改变时,页面不会去重新加载。
hash(#)是URL 的锚点,代表的是网页中的一个位置,单单改变#后的部分(/#/..),浏览器只会加载相应位置的内容,不会重新加载网页,也就是说 #是用来指导浏览器动作的,对服务器端完全无用,HTTP请求中不包括#;同时每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置;所以说Hash模式通过锚点值的改变,根据不同的值,渲染指定DOM位置的不同组件。
History模式
HTML5 History API提供了一种功能,能让开发人员在不刷新整个页面的情况下修改站点的URL,就是利用 history.pushState API 来完成 URL 跳转而无须重新加载页面;
由于hash模式会在url中自带#,如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。
当使用这种历史模式时,URL 会看起来很 "正常",例如
https://example.com/user/id。漂亮!
不过,问题来了。由于我们的应用是一个单页的客户端应用,如果路由不存在,并且没有适当的服务器配置,用户在浏览器中直接访问就会得到一个 404 错误。这在用户体验上不是太好。
解决办法如下:
服务端
路由部分(这样在路由匹配不到的时候,可以显示404页面,当然也可以根据需求使用路由守卫来处理,附属上找到的例子)
abstract模式
abstract模式是使用一个不依赖于浏览器的浏览历史虚拟管理后端。不依赖于浏览器的api实现路由的跳转管理。
使用SSR服务端渲染的时候用到这种模式
通过查询,我发现这个模式的另一个用途,一起总结下来,利用到了abstract这种与浏览器分离的路由模式(仅限于旧版本的vue2.x,新的vue3无法以此种方式尝试验证,createMemoryHistory还是用于SSR使用)
抽屉显例
/*route.js*/
const routes = [
{
path: "/",
redirect: "abstract-route",
},
{
path: "/embed-route",
name: "embedded",
component: () =>
import("../views/embed.vue"),
},
{
path: "/abstract-route",
name: "abstract",
component: () =>
import("../views/abstract.vue"),
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
/*abstract.vue*/
<template>
<div>
<RouterDrawer
:visible.sync="visible"
:path="{ name: 'embedded' }"
size="50%"
title="drawer comps"
></RouterDrawer>
<el-button @click="visible = true">open drawer</el-button>
</div>
</template>
/*embedded.vue*/
<template>
<div>
embedded views
</div>
</template>
router-drawer 封装
当前项目默认是history 的路由模式,因此在进入abstract页面时,浏览器Url为http://localhost:8080/abstract-route,而router-drawer要做的是在此基础上,重新实例化一个abstract模式的路由,然后在组件当中利用<router-view />去挂载要被内嵌的目标页面。即:
<template>
<el-drawer
:visible.sync="visible"
v-bind="$attrs"
:before-close="handleClose"
>
<router-view />
</el-drawer>
</template>
<script>
import { routes } from "../router/index";
import VueRouter from "vue-router";
export default {
name: "router-drawer",
props: {
path: {
type: Object,
required: true,
},
visible: {
type: Boolean,
required: true,
default: false,
},
},
// 此处实例化一个新的router来配合当前页面的router-view
router: new VueRouter({
mode: "abstract",
base: "/",
routes,
}),
methods: {
handleClose() {
this.$emit("update:visible", false);
},
},
mounted() {
console.log("drawer router", this.$router);
this.$router.push(this.path);
},
};
</script>