刚接触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前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。