# 什么是骨架屏

骨架屏可以理解为是当数据还未加载进来前,页面的一个空白版本,一个简单的关键渲染路径。可以看一下下面 Facebook 的骨架屏实现,可以看到在页面完全渲染完成之前,用户会看到一个样式简单,描绘了当前页面的大致框架的骨架屏页面,然后骨架屏中各个占位部分被实际资源完全替换,这个过程中用户会觉得内容正在逐渐加载即将呈现,降低了用户的焦躁情绪,使得加载过程主观上变得流畅。

可以看一下下面的示例图,第一个为骨架屏,第二个为菊花图,第三个为无优化,可以看到相比于传统的菊花图会在感官上觉得内容出现的流畅而不突兀,体验更加优良

# 骨架屏原理

生成骨架屏的方式主要有:

  1. 手写 HTML、CSS 的方式为目标页定制骨架屏 做法可以参考<Vue 页面骨架屏注入实践> (opens new window),主要思路就是使用 vue-server-renderer 这个本来用于服务端渲染的插件,用来把我们写的.vue 文件处理为 HTML,插入到页面模板的挂载点中,完成骨架屏的注入。这种方式不甚文明,如果页面样式改变了,还得改一遍骨架屏,增加了维护成本。骨架屏的样式实现参考 CodePen 使用图片作为骨架屏;简单暴力,让 UI 同学花点功夫吧哈哈;小米商城的移动端页面采用的就是这个方法,它是使用了一个 Base64 的图片来作为骨架屏。

  2. vue-skeleton-webpack-plugin (预渲染插件)它将插入骨架屏的方式由手动改为自动,原理在构建时使用 Vue 预渲染功能,将骨架屏组件的渲染结果 HTML 片段插入 HTML 页面模版的挂载点中,将样式内联到 head 标签中。这个插件可以给单页面的不同路由设置不同的骨架屏,也可以给多页面设置,同时为了开发时调试方便,会将骨架屏作为路由写入 router 中,可谓是相当体贴了。

  3. 自动生成并自动插入静态骨架屏 这种方法跟第一种方法类似,不过是自动生成骨架屏,可以关注下饿了么开源的插件 page-skeleton-webpack-plugin ,它根据项目中不同的路由页面生成相应的骨架屏页面,并将骨架屏页面通过 webpack 打包到对应的静态路由页面中,不过要注意的是这个插件目前只支持 history 方式的路由,不支持 hash 方式,且目前只支持首页的骨架屏,并没有组件级的局部骨架屏实现,作者说以后会有计划实现(issue9)。

还有一个骨架生成工具dps(draw-page-structure) (opens new window),可以自动生成骨架节面,不过本人在 vue 项目中路由为 hash 的模式下,没有真正生成。

最终作者在自己的项目中使用了 vue-skeleton-webpack-plugin 来实现骨架屏幕,综合所有方案的对比请大家参考下图