刚接触Vue Router的同学,大概率会纠结,history模式到底是啥?项目里咋用?部署到服务器咋老报404?这篇文章把这些问题拆碎了讲,看完你就门儿清~
Vue Router history模式是啥?
先回忆下Vue Router的路由模式,默认是hash模式,URL里带个,比如http://xxx.com/#/about,而history模式是另一种路由模式,它的URL长这样:http://xxx.com/about,没有,更像普通网站的URL,好看又专业。
它能实现这效果,靠的是HTML5 History API里的pushState和replaceState方法,这俩方法允许咱在不刷新页面的情况下,修改浏览器的历史记录,同时改变URL,Vue Router就是基于这俩API,让前端路由切换时,URL跟着变,但页面不用重新加载,体验更流畅。
举个例子:用户点导航栏的“关于我们”,history模式下,URL从首页变成/about,同时Vue Router加载对应的About组件,整个过程页面不刷新,用户感觉跟原生APP切换页面一样丝滑。
咋在项目里开启history模式?
配置特别简单,就改一行代码!在创建Vue Router实例的时候,把mode属性设为'history'就行,看例子:
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'
Vue.use(VueRouter)
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
// 关键配置:mode: 'history'
const router = new VueRouter({
mode: 'history',
routes
})
export default router
配置完后,启动项目看看URL,原来的没了,路由切换时URL也会跟着变,比如从根路径跳到About页面,URL变成http://localhost:8080/about,是不是清爽多了?
不过要注意:开发环境(比如Vue CLI启动的dev server)里,这种配置不会有问题,因为开发服务器已经帮咱处理了路由跳转,但部署到生产环境时,麻烦才刚开始……
部署history模式项目,为啥总遇到404?咋解决?
很多同学部署后,直接访问首页()没问题,但刷新子路由(比如/about)就报404,这不是你代码写错了,而是服务器和单页应用(SPA)的工作逻辑导致的。
咱得先明白:SPA的路由是前端路由,意思是所有路由逻辑都在浏览器里处理,服务器上真正存在的文件只有index.html,其他像/about这种路径,服务器里根本没有对应的文件,所以当你直接在浏览器输入/about,服务器会找这个路径的文件,找不到就返回404。
解决思路很简单:让服务器把所有路由请求,都转发到index.html,让前端Vue Router来处理路由,下面分不同服务器讲配置方法:
Nginx服务器配置
打开Nginx的配置文件(一般在/etc/nginx/conf.d/或/usr/local/nginx/conf/),在server块里加这段:
location / {
root /usr/share/nginx/html; # 你的项目dist目录路径
index index.html index.htm;
try_files $uri $uri/ /index.html; # 关键配置:尝试访问文件→目录→转发到index.html
}
try_files的作用是:先找请求的文件(比如/about对应的文件,不存在),再找对应的目录(也不存在),最后转发到/index.html,这样前端Vue Router就能接管路由,不会404了。
Apache服务器配置
需要开启mod_rewrite模块,然后在项目根目录(dist目录)新建.htaccess文件,写入:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
解释下:先开Rewrite引擎,然后判断请求的文件(!-f)和目录(!-d)是否不存在,如果不存在,就转发到index.html。
Node.js(Express框架)配置
如果用Node.js做后端,比如Express,需要在代码里处理所有路由,转发到index.html,示例代码:
const express = require('express')
const path = require('path')
const app = express()
// 静态文件托管(dist目录)
app.use(express.static(path.join(__dirname, 'dist')))
// 所有请求都返回index.html
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist', 'index.html'))
})
const port = process.env.PORT || 3000
app.listen(port, () => {
console.log(`Server running on port ${port}`)
})
这样不管用户访问哪个路径,都会返回index.html,前端路由就能正常工作啦~
history模式和hash模式有啥区别?咋选?
很多同学纠结选哪个模式,咱从URL外观、原理、后端配置、兼容性这几点对比下:
| 对比项 | history模式 | hash模式 |
|---|---|---|
| URL外观 | 无#,如http://xxx.com/about |
有#,如http://xxx.com/#/about |
| 底层原理 | HTML5 History API(pushState/replaceState) |
监听hashchange事件(URL中#后的变化) |
| 后端配置 | 需要配置(否则刷新404) | 不需要(因为#后的内容不会传给服务器) |
| 兼容性 | IE10+(HTML5新特性) | IE8+(hashchange事件兼容性好) |
| 适用场景 | 追求URL美观、不需要兼容旧浏览器 | 需要兼容IE8/9,或快速部署不想配后端 |
简单说:如果项目面向现代浏览器,想要更专业的URL,选history模式(记得配后端);如果要兼容老浏览器,或者快速上线不想折腾服务器,选hash模式更省心。
用history模式开发,这些坑要避开!
除了部署,开发过程中还有些细节得注意,不然容易踩坑:
开发环境 vs 生产环境
Vue CLI的开发服务器(npm run serve)已经处理了路由转发,所以开发时刷新子路由不会404,但生产环境必须配服务器,否则一刷新就崩,所以开发时要记得,部署前先测服务器配置。
路由守卫的使用
不管是history还是hash模式,路由守卫(比如beforeEach)的逻辑是一样的,但要注意:history模式下,pushState不会触发popstate事件(比如前进后退会触发),所以如果在守卫里处理页面跳转逻辑,要确保逻辑对所有路由变化生效,别只依赖特定事件。
SEO优化咋搞?
SPA的SEO天生弱,因为爬虫(比如百度、谷歌)爬取页面时,可能不执行JS,导致看不到前端渲染的内容,history模式下,想做SEO可以这么搞:
- 服务端渲染(SSR):用Vue SSR把页面在服务器渲染成HTML,再返回给浏览器,比如Nuxt.js就是基于Vue的SSR框架,能解决SEO问题。
- 预渲染(Prerender):用
prerender-spa-plugin这类工具,在构建时生成每个路由的静态HTML文件,比如配置后,/about会生成about/index.html,爬虫能直接拿到内容。
举个预渲染的简单配置(Vue CLI项目):
// vue.config.js
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const path = require('path')
module.exports = {
configureWebpack: () => {
if (process.env.NODE_ENV === 'production') {
return {
plugins: [
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, 'dist'),
routes: ['/', '/about'], // 要预渲染的路由
})
]
}
}
}
}
这样构建后,dist目录下会生成每个路由的静态HTML,SEO友好度up~
404页面咋处理?
想做自定义404页面,得在路由配置里加通配符路由:
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About },
{ path: '*', component: NotFound } // 匹配所有未定义的路由
]
但注意:必须先配服务器转发,否则服务器返回404,根本到不了前端路由这一步,所以得先按前面讲的配好服务器,再加前端的404路由,这样用户访问不存在的路径时,才会显示自定义的NotFound组件。
常见问题Q&A
最后集中解答几个高频问题,帮你快速排雷~
Q1:history模式下,刷新页面报404,咋解决?
A:看部署部分的服务器配置,把所有请求转发到index.html,不同服务器配置方法不一样,Nginx、Apache、Node.js的配置前面都讲过,照着配就行。
Q2:IE9能跑history模式吗?
A:不行,因为history模式依赖HTML5 History API,而IE9及以下不支持这组API,如果要兼容IE9,只能用hash模式。
Q3:history模式下,能设置页面标题吗?
A:当然能!可以用路由守卫或者Vue Router的afterEach钩子,结合document.title设置。
router.afterEach((to) => {
document.title = to.meta.title || '默认标题'
})
// 路由配置里加meta
{ path: '/about', component: About, meta: { title: '关于我们' } }
Q4:history模式下,能传参吗?和hash模式有区别吗?
A:传参方式和模式没关系~不管是params、query,还是动态路由(如/user/:id),用法都一样,比如用$router.push({ name: 'User', params: { id: 123 } }),URL会变成/user/123(history模式)或/#/user/123(hash模式)。
到这儿,Vue Router history模式的核心知识点就讲完啦~记住核心逻辑:它靠HTML5 History API实现美观URL,但部署要配服务器转发;和hash模式各有优劣,选的时候看项目需求,下次再遇到history模式的问题,回忆下这篇内容,应该能快速解决~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网



发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。