相关阅读:
Vue 中的路由实现原理
默认情况下,Vue 构建出的都是一个单页应用,即所谓的SPA
,此类应用只有一个.html
文件,通过 js 操作路由,实现一个网页,多种视图
的效果。Vue 为我们提供了方便快速的构建页面路由的工具——VueRouter。
我们在配置路由的时候,会碰到两种路由模式,一种是Hash
模式,一种是History
模式,两者最直观的区别就是在Hash
模式中,URL 会有一个"#“号在路由前面(比如助手的 app 页面就会有一个”#“号),而History
模式则没有。
这是因为Hash
模式采用 URL 的 hash(不是哈希表的那个 hash)来模拟
一个完整的 URL。
我第一学期在完成助手前端部的仿制页面作业时,是这样写 a 标签的:
|
|
当时学长跟我说,href
标签不要留空,可以写一个”#“号代替。这是一个好习惯,虽然留空也没有报错,但事实上,留空时点击该标签时会刷新页面,而写了”#“后则只会跳转到页面顶部,但无论何时,都尽量不要让某个attribute
值为空。
"#"
实际上是一个锚点,代表网页中的一个位置,其右面的字符,就是该位置的标识符。例如href="#app"
将滚动到当前页面中id="app"
的元素。正常情况下,当浏览器地址栏地址改变,浏览器会重新加载页面,而如果只是 hash 部分("#“后面)修改的话,则不会重新加载,这就是单页前端路由的原理,即允许根据不同的路由页面局部更新而不刷新整个页面。对于服务器来说,"#“后面的内容是会被自动忽略的,即 hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,所以对后端完全没有影响。
H5 新增了history
的pushState接口,同样也允许前端操作改变路由地址但是不触发页面刷新,history 模式即利用这一接口来实现。因此使用 history 模式可以去掉路由中的#号。
如何在 Nginx 中挂载 History 路由模式的 Vue 应用
除了外观和实现方式上的不同,Hash
和History
模式在部署时也有不同的要求
Hash
模式下,仅 hash 符号之前的内容会被包含在请求中,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。
History
模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如果后端缺少对 URL 的路由处理,将返回 404 错误。
当把单页应用部署到服务端后,由于我们构建的是一个单页应用,所以使用Hash
路由模式的页面不会出现问题,而对于使用History
模式的单页来说,在访问网页时的 URL 类似于http://xxx.com/vueapp/home
这样的结构,这里vueapp
是应用名称,在其之后使用/home
对服务器而言相当于在vueapp
目录下访问home
子目录或者文件。正如之前所说的,history
模式下调用pushState
接口,可以实现“改变路由地址但是不触发页面刷新”,但是如果用户手动刷新后,服务器就会把当前路由当成一个子目录或者文件去寻址,那当然会报 404 错误。
为了解决这个问题,我们需要配置Nginx
(或其他服务端),并在其中增加一个覆盖所有情况的候选资源,使得如果 URL 匹配不到任何静态资源,则返回同一个index.html
页面,这个页面就是你 app 依赖的页面。这是为了让浏览器在任何情况下都能指向同一个网页,而不会在跳转时产生 404 错误。而相应的,这样子你的页面就不会
再产生 404 错误界面了。
|
|
这句配置的意思就是,拿到一个地址,先根据地址尝试找对应文件,找不到再试探地址对应的文件夹,再找不到就返回/vueapp/index.html。这样对于我们的单页应用而言,再刷新页面就不会出现 404 了
配置完重启下 Nginx 服务即可(CentOS)
|
|
“给个警告,因为这么做以后,你的服务器就不再返回 404 错误页面,因为对于所有路径都会返回
index.html
文件。为了避免这种情况,你应该在 Vue 应用里面覆盖所有的路由情况,然后再给出一个 404 页面。”
1 2 3 4
const router = new VueRouter({ mode: "history", routes: [{ path: "*", component: NotFoundComponent }], });
使用History
模式的单页在部署时同样需要在项目的Vue.config.js
下对publicPath
进行路径的配置,将其设置为:
|
|
在router/index.js
下修改base
路径:
|
|
这样一来在项目和服务端就都完成了配置,history
模式的路由就可以正常显示内容了!