Skip to content

1.解释下spa的原理 及 spa路由模式 及 SPA首屏优化 及部署后404问题

参考:SPA 路由三部曲之核心原理 作者:京东设计中心JDC-杨小璐 链接

定义

SPA就是单页WEB应用。SPA离不开前端路由的支持。

前端路由的发展

既然说到了前端路由,就要回溯下它的发展史

后端路由

早期,路由是后端的概念,页面渲染完全依靠服务器。用户进行页面切换的时候,浏览器发送不同的URL请求,通过解析不同的URL地址进行路由匹配,模板拼接好后将HTML字符串返回给前端,浏览器拿到HTML字符串后就交给浏览器解析展示,这也就是所谓的服务端渲染。

  • 优点:后端有完整的HTML代码,爬虫更容易获取信息,有利于SEO;对于客户端的资源占用更少
  • 缺点:每跳转到不同的 URL都会重新访问服务器,给服务端增加压力;没有合理地利用缓存。

过渡方案AJAX

AJAX是浏览器实现异步加载的一种技术方案。

前端路由

前端路由的特点就是在不完全刷新页面的情况下进行视图的切换,页面的URL变了,但并没有重新加载。 前端路由使页面渲染由服务器渲染变为了前端渲染,请求一个URL时,服务端返回的是一个空的HTML

html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Demo</title>
  <link href="app.css" rel="stylesheet"/>
</head>
<body>
  <div id="app"></div>
  <script type="text/javascript" src="app.js"></script>
</body>
</html>

我们看到的页面是通过js渲染出来的

  • 优点:缓解服务端压力;
  • 缺点: 渲染速度不如服务端渲染;不利于SEO优化

前端路由核心原理

前端路由的展示方式有 2 种:

  • 带有hash的前端路由:地址栏 URL 中有 #,即 hash 值,不好看,但兼容性高。
  • 不带hash的前端路由:地址栏 URL 中没有 #,好看,但部分浏览器不支持,还需要后端服务器支持。

原理:本质上就是通过监测URL的变化,截获URL地址,通过解析、匹配路由规则实现UI更新

hash

一个完整的URL包括:协议、域名、端口、虚拟目录、文件名、参数、锚。

hash值指的是URL地址中的锚部分,也就是#部分。hash也称为锚点,用来做页面定位的。

hash值更新有以下几个特点:

  • hash值是网页的标志位,HTTP请求不包含锚部分,对后端没有影响
  • 因为 HTTP 请求不包含锚部分,所以 hash 值改变时,不触发网页重载
  • 改变 hash 值会改变浏览器的历史记录
  • 改变 hash 值会触发 window.onhashchange() 事件

改变hash值有以下几种方式

  • 通过a标签跳转
  • 通过设置window.location.hash
  • 浏览器前进(history.forword)后退(history.back)

hash模式路由就是利用onhashchange事件监听URL的变化,从而触发DOM操作来模拟页面跳转

history

浏览器有一个类似栈的历史记录,遵循先进后出的规则。URL的每次改变,包括hash值的改变都会在浏览器中形成一条历史记录。window对象通过history对象提供对浏览器历史记录的访问能力。

  • history.lengh:出于安全考虑,History对象不允许未授权代码访问历史记录中其他页面的URLS,但可以通过history.length访问历史记录对象的长度。
  • history.back():返回上一个历史记录,类似浏览器的后退按钮
  • history.forward(): 前进到下一个历史记录,类似浏览器前进按钮
  • history.go(n): 跳转到相应的访问记录,n > 0,则前进,n < 0,则后退

为了配合单页应用的发展,HTML5对history API新增了两个方法

  • pushState(state, title, URL)

    • state: 用于存储该URL对应的状态对象,通过history.state获取
    • title:标题,不支持🈲
    • url:定义新的历史 URL 记录,需要注意,新的 URL 必须与当前 URL 同源,不能跨域。 TIPS: pushState 函数会向浏览器的历史记录中添加一条,history.length 的值会 +1,当前浏览器的 URL 变成了新的 URL。它仅仅将浏览器的 URL 变成了新的 URL,页面不会加载、刷新。
  • replaceState(state,title, URL) replaceState 的使用与 pushState 非常相似,都是改变当前的 URL,页面不刷新。区别在于 replaceState 是修改了当前的历史记录项而不是新建一个,history.length 的值保持不变。

onpopstate()

通过pushState和replaceState改变的历史记录,点击浏览器的前进后退页面是没有反应的,为了配合上述两个API,HTML5还新增了一个事件,用于监听URL历史记录的改变:window.onpopstate()

SPA首屏加载慢怎么解决

加载慢的原因

  • 网络延时原因
  • 资源文件体积过大
  • 资源重复发送请求去加载
  • 加载脚本的时候,渲染被阻塞

解决方案

  • 减小入口文件体积

    常用的手段是路由懒加载,把不同的路由对应的组件分割成不同的代码块,待路由被请求的时候会被单独打包路由,使得入口文件变小,加载速度大大增加

    在vue-router配置路由时,采用动态加载路由的形式

    js
      routes: [
        path: 'Blogs',
        name: 'Test',
        component: () => import('./components/test.vue')
      ]

    以函数的形式加载路由,这样就可以把各自的路由文件分别打包,只有在解析给定的路由时,才会加载路由组件

  • 静态资源本地缓存

    • 采用HTTP缓存,设置Cache-Control、Last-Modified,Etag等
    • 采用Service Worker离线缓存
    • 合理利用localStorage
  • UI框架按需加载(element等)

    js
      import { Button, Input, Pagination, Table, TableColumn, MessageBox } from 'element-ui';
      Vue.use(Button)
  • 图片资源的压缩

    使用雪碧图、在线字体图标等

  • 组件重复打包

    修改webpack CommonsChunkPlugin的配置

    js
      // 将使用3次以上的包抽离出来,避免重复加载
      minChunks: 3
  • 使用SSR

    SSR(Server side ),也就是服务端渲染,组件或页面通过服务器生成html字符串,再发送到浏览器 从头搭建一个服务端渲染是很复杂的,vue应用建议使用Nuxt.js实现服务端渲染

KESHAOYE-知识星球