13.1 Hash模式与History模式区别
前端路由中,不管是什么实现模式,都是客户端的一种实现方式,也就是当路径发生变化的时候,是不会向服务器发送请求的。
如果需要向服务器发送请求,需要用到ajax方式。
两种模式的区别
首先是表现形式的区别
Hash模式
当然这种模式相对来说比较丑,路径中带有与数据无关的符号,例如#与?
History模式
https://www.baidu.com/showlist/22256
1
History模式是一个正常的路径的模式,如果要想实现这种模式,还需要服务端的相应支持。
下面再来看一下两者原理上的区别。
Hash模式是基于锚点,以及onhashchange事件。
History模式是基于HTML5中的History API
也就是如下两个方法
history.pushState( ) IE10以后才支持
history.replaceState( )
2、解决方案
为了解决这个问题,我们需要在服务器端进行相关配置,让所有的路由都指向同一个入口文件(比如 index.html),由前端路由来处理 URL 请求,返回对应的页面内容。
具体的配置方式取决于对应项目使用的服务器环境,常见的有 Apache、Nginx 等。
以 Nginx 为例,需要在服务器配置文件(通常是 nginx.conf.js )中添加以下配置,以将所有请求都代理到 Vue 应用程序的入口文件:
try_file $uri$uri/ index.html
同时需要注意在使用 History 模式时,需要保证所有路由的访问路径都指向 index.html,否则仍然会出现404错误。
这些配置将确保在 Vue 应用程序中使用 history 模式时,服务器能够正确地处理所有路由请求,并返回正确的页面。
History模式需要服务器的支持,为什么呢?
所以说,在服务端应该除了静态资源外都返回单页应用的index.html
下面我们开始history模式来演示一下对应的问题。
首先添加一个针对404组件的处理
首先在菜单栏中添加一个链接:
<div class="content left">
<ul>
<li><router-link to="/users"> 用户管理</router-link></li>
<li><router-link to="/rights"> 权限管理</router-link></li>
<li><router-link to="/goods"> 商品管理</router-link></li>
<li><router-link to="/orders"> 订单管理</router-link></li>
<li><router-link to="/settings"> 系统设置</router-link></li>
<li><router-link to="/about"> 关于</router-link></li>
</ul>
</div>
这里我们添加了一个“关于”的链接,但是我们没有为其定义相应的组件,所以这里需要处理404的情况。
const NotFound = {
template: <div> 你访问的页面不存在!! </div>
,
};
在程序中添加了一个针对404的组件。
const router = new VueRouter({
mode: “history”,
const router = new VueRouter({
mode: “history”,
routes: [
{ path: “/login”, component: Login },
{ path: “*”, component: NotFound },
{
path: “/”,
component: App,
redirect: “/users”,
children: [
{
path: “/users”,
component: Users,
meta: {
auth: true,
},
// beforeEnter(to, from, next) {
// if (window.isLogin) {
// next();
// } else {
// next(“/login?redirect=” + to.fullPath);
// }
// },
},
{ path: “/userinfo/:id”, component: UserInfo, props: true },
{ path: “/rights”, component: Rights },
{ path: “/goods”, component: Goods },
{ path: “/orders”, component: Orders },
{ path: “/settings”, component: Settings },
],
},
],
});
在上面的代码中,指定了处理404的路由规则,同时将路由的模式修改成了history模式。同时,启用这里启用了其它的组件的路由规则配置,也就是不在login方法中使用addRoutes方法来动态添加路由规则了。
login 方法修改成如下形式:
login() {
// window.isLogin = true;
window.sessionStorage.setItem(“isLogin”, true);
if (this.KaTeX parse error: Expected '}', got 'EOF' at end of input: … // this.router.addRoutes([
// {
// path: “/”,
// component: App,
// redirect: “/users”,
// children: [
// {
// path: “/users”,
// component: Users,
// meta: {
// auth: true,
// },
// // beforeEnter(to, from, next) {
// // if (window.isLogin) {
// // next();
// // } else {
// // next(“/login?redirect=” + to.fullPath);
// // }
// // },
// },
// { path: “/userinfo/:id”, component: UserInfo, props: true },
// { path: “/rights”, component: Rights },
// { path: “/goods”, component: Goods },
// { path: “/orders”, component: Orders },
// { path: “/settings”, component: Settings },
// ],
// },
// ]);
this.
r
o
u
t
e
r
.
p
u
s
h
(
t
h
i
s
.
router.push(this.
router.push(this.route.query.redirect);
} else {
this.$router.push(“/”);
}
}
现在已经将前端vue中的代码修改完毕了,下面我们要将页面的内容部署到node.js服务器中。
而且上面的代码中,我们使用了sessionStorage来保存登录用户的信息,不在使用window下的isLogin
对应的data内容下的代码也要修改:
const Login = {
data() {
return {
isLogin: window.sessionStorage.getItem(“isLogin”),
};
},
路由守卫中的代码进行如下修改:
jsrouter.beforeEach((to, from, next) => {
//to:去哪个页面,from来自哪个页面,next继续执行.
if (window.sessionStorage.getItem(“isLogin”)) {
//用户已经登录
if (to.path === “/login”) {
// 用户已经登录了,但是又访问登录页面,这里直接跳转到用户列表页面
next(“/”);
} else {
//用户已经登录,并且访问其它页面,则运行访问
next();
}
} else {
//用户没有登录,并且访问的就是登录页,则运行访问登录页
if (to.path === "/login") {
next();
} else {
//用户没有登录,访问其它页面,则跳转到登录页面。
next("/login?redirect=" + to.fullPath);
}
}
});
在上面的代码中,我们也是通过sessionStorage来获取登录信息。
index.html完整代码如下:
下面看一下具体的node代码的实现。
app.js文件中的代码如下:
connect-history-api-fallback模块的安装如下(注意在上面的代码中还没有使用该模块)
npm install --save connect-history-api-fallback
1
下面还需要安装express
npm install express
1
启动服务
并且当我们去单击左侧的菜单的时候,可以实现页面的切换,同时单击“关于”的时候,会出现NotFound组件中的内容。
经过测试发现好像没有什么问题,那这是什么原因呢?你想一下当我们单击左侧菜单的时候,路由是怎样工作的呢?
所以说现在整个操作都是在客户端完成的。
但是,当我刷新了浏览器以后,会出现怎样的情况呢?
以上就是如果vue-router开启了history模式后,出现的问题。
下面解决这个问题,在服务端启用connect-history-api-fallback模块就可以了,如下代码所示:
const path = require(“path”);
//导入处理history模式的模块
const history = require(“connect-history-api-fallback”);
const express = require(“express”);
const app = express();
//注册处理history模式的中间件
app.use(history());
//处理静态资源的中间件
app.use(express.static(path.join(__dirname, “…/web”)));
app.listen(3000, () => {
console.log(“服务器开启”);
});
服务端的代码做了修改以后,一定要服务端重新启动node app.js
然后经过测试以后发现没有问题了。
那么现在你考虑一下,具体的工作方式是什么?
当我们在服务端开启对history模式的支持以后,我们刷新浏览器,会想服务器发送请求,例如:http://localhost:3000/orders