一、SPA 理解
-
SPA 也是单页面应用的意思,通俗来说就是只有一个 index.html 页面,内部通过路由来实现页面的局部切换,公共资源部分只加载一次
-
SPA 将所有的活动局限于一个 Web 页面中,仅在该 Web 页面初始化时加载相应的 HTML 、 JavaScript 、 CSS 。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转,而是利用 JavaScript 动态的变换 HTML(采用的是 div 切换显示和隐藏),从而实现UI与用户的交互。在 SPA 应用中,应用加载之后就不会再有整页刷新。相反,展示逻辑预先加载,并有赖于内容Region(区域)中的视图切换来展示内容
二、SPA 和 MPA 的区别
- MPA 也是多页面应用的意思,就是每个页面都是一个主页面,都是独立的,当我们在访问另一个页面的时候,都需要重新加载他们相应的 HTML 、 JavaScript 、 CSS
| SPA | MPA | |
|---|---|---|
| 结构 | 一个主页面 + 许多模块的组件 | 多完整的页面 |
| 体验 | 页面切换快,体验佳;当初次加载文件过多时,需要做相关的调优 | 页面切换慢,网速慢的时候,体验尤其不好 |
| 资源加载 | 组件公用的资源只需要加载一次 | 每个页面都要自己加载公用的资源 |
| 适用场景 | 对体验度和流畅度有较高要求的应用,不利于 SEO(可借助 SSR 优化 SEO) | 适用于对 SEO 要求较高的应用 |
| 适用场景 | 可以使用 hash ,也可以使用 history | history |
| 数据传递 | 单页面引用,可以使用全局状态管理(VueX) | 通过url、cookie、localStorage等传递 |
三、SPA 优缺点
3-1 优点
- 良好的交互体验,能提升页面切换体验,用户在访问应用页面是不会频繁的去切换浏览页面,从而避免了页面的重新加载
- 前后端分离开发,单页Web应用可以和 RESTful 规约一起使用,通过 REST API 提供接口数据,并使用 Ajax 异步获取,这样有助于分离客户端和服务器端工作。更进一步,可以在客户端也可以分解为静态页面和页面交互两个部分
- 减轻服务器压力,服务器只用出数据就可以,不用管展示逻辑和页面合成,吞吐能力会提高几倍
- 共用一套后端程序代码,不用修改后端程序代码就可以同时用于 Web 界面、手机、平板等多种客户端
3-2 缺点
- 不利于SEO,由于所有的内容都在一个页面中动态替换显示,所以在SEO上其有着天然的弱势,所以如果你的站点对SEO很看重,且要用单页应用,那么就做些静态页面给搜索引擎用吧
- 浏览器前进、后退管理,由于单页Web应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理,当然此问题也有解决方案,比如利用URI中的散列+iframe实现
- 初次加载耗时多,为实现单页Web应用功能及显示效果,需要在加载页面的时候将JavaScript、CSS统一加载,部分页面可以在需要的时候加载。所以必须对JavaScript及CSS代码进行合并压缩处理
四、SPA 首屏加载优化
4-1 首屏加载慢的原因
首屏时间指的是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时整个网页不一定要全部渲染完成,但需要展示当前页面需要的内容,在页面渲染的过程,导致加载速度慢的因素可能如下:
- 网络延时问题
- 资源文件体积过大
- 资源重复发送请求去加载了
- 加载脚本的时候,渲染内容堵塞了
4-2 首屏加载慢的解决方案
路由动态加载
- 按需加载指的就是按照当前呈现的不同页面加载不同的文件,而不是最开始就把所有文件都加载出来,从而避免首屏加载很慢
- 当首屏加载完毕后,设备和网络处于空闲状态,再去对其他路由组件进行预加载,以便提升页面切换性能
- 根据路由拆分减少初始加载体积,利用异步加载方式,在路由注册时提供异步拉取组件的方法,仅在需要进入对应路由时,对应组件才会被加载进来
// 在`vue-router`配置路由的时候,采用动态加载路由的形式
routes:[
{
path: 'Blog',
name: 'Blog',
component: () => import('./components/Blog.vue')
}
]
UI组件按需加载
// 引用了整个库
import ElementUI from 'element-ui'
Vue.use(ElementUI)
// 按需引用
import { Button, Input, Pagination, Table, TableColumn, MessageBox } from 'element-ui';
Vue.use(Button)
Vue.use(Input)
Vue.use(Pagination)
修改webpack配置,避免重复打包
在多个页面引用了同一个常用库的时候会造成该库的重复下载
// 解决方案:在 webpack的 config 文件中,修改 CommonsChunkPlugin 的配置
minChunks: 3
minChunks 为3表示会把使用3次及以上的包抽离出来,放进公共依赖文件,避免了重复加载组件
使用webpack插件,开启GZip压缩
// 安装 compression-webpack-plugin
cnmp i compression-webpack-plugin -D
// 修改 webpack 配置,再拆完包之后,使用 gzip 做一下压缩
const CompressionPlugin = require('compression-webpack-plugin')
configureWebpack: (config) => {
if (process.env.NODE_ENV === 'production') {
// 为生产环境修改配置...
config.mode = 'production'
return {
plugins: [new CompressionPlugin({
test: /.js$|.html$|.css/, //匹配文件名
threshold: 10240, //对超过10k的数据进行压缩
deleteOriginalAssets: false //是否删除原文件
})]
}
}
图片资源的压缩
页面中使用到的icon,可以使用在线字体图标,或者雪碧图,将众多小图标合并到同一张图上,用以减轻 http 请求压力
SSR 服务端渲染
服务端渲染就是组件或页面通过服务器生成html字符串,再发送到浏览器
五、SPA 体验优化
-
构建骨架图,SPA 首屏加载面临较长时间白屏,骨架图是一个完美的”缓兵之计”,相当于加载到下个界面时先把下个页面的雏形加载出来,再加载其余的组件,做到缓冲作用,配合 PWA 首屏缓存,骨架图可实现瞬间加载的展示,首屏视觉上有冲击性地提升
-
页面切换时的转场动画,无论如何优化性能加载,在页面切换时候依旧需要获取页面数据,若处理不好,可能会在数据返回前有短暂的不友好”空白”,在大多数原生应用,转场动画属于标配,即使组件的数据已经完全加载,在切换至新页面瞬间,依旧需要页面渲染时间,这段时间可能导致页面短暂空白或者”视觉阻塞”,通过转场动画时间,可以很好地缓解这个问题,大多数页面保证在转场动画完毕之后依然渲染完毕