什么是骨架屏

什么是骨架屏呢?骨架屏(Skeleton Screen)是指在页面数据加载完成前,先给用户展示出页面的大致结构(灰色占位图),在拿到接口数据后渲染出实际页面内容然后替换掉。Skeleton Screen 是近两年开始流行的加载控件,本质上是界面加载过程中的过渡效果。

假如能在加载前把网页的大概轮廓预先显示,接着再逐渐加载真正内容,这样既降低了用户的焦灼情绪,又能使界面加载过程变得自然通畅,不会造成网页长时间白屏或者闪烁。这就是 Skeleton Screen !

Skeleton Screen 能给人一种页面内容“已经渲染出一部分”的感觉,相较于传统的 loading 效果,在一定程度上可提升用户体验。

骨架屏的实现方案

目前生成骨架屏的技术方案大概有三种:

使用图片、svg 或者手动编写骨架屏代码:使用 HTML + CSS 的方式,我们可以很快的完成骨架屏效果,但是面对视觉设计的改版以及需求的更迭,我们对骨架屏的跟进修改会非常被动,这种机械化重复劳作的方式此时未免显得有些机动性不足;

通过预渲染手动书写的代码生成相应的骨架屏:该方案做的比较成熟的是 vue-skeleton-webpack-plugin,通过 vueSSR 结合 webpack 在构建时渲染写好的 vue 骨架屏组件,将预渲染生成的 DOM 节点和相关样式插入到最终输出的 html 中。

// webpack.conf.js

const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin');

plugins: [

//...

new SkeletonWebpackPlugin({

webpackConfig: {

entry: {

app: resolve('./src/entry-skeleton.js')

}

}

})

]

该方案的前提同样是编写相应页面的骨架屏组件,然后预渲染生成骨架屏所需的 DOM 节点,但由于该方案与 vue 相关技术直接关联,在当今前端框架三分天下的大环境下,我们可能需要一个更加灵活、可控的方案;

3 . 饿了么内部的生成骨架页面的工具:该方案通过一个 webpack 插件 page-skeleton-webpack-plugin 的方式与项目开发无缝集成,属于在自动生成骨架屏方面做的非常强大的了,并且可以启动 UI 界面专门调整骨架屏,但是在面对复杂的页面也会有不尽如人意的地方,而且生成的骨架屏节点是基于页面本身的结构和 CSS,存在嵌套比较深的情况,体积不会太小,并且只支持 history 模式。

// webpack.conf.js

const HtmlWebpackPlugin = require('html-webpack-plugin')

const { SkeletonPlugin } = require('page-skeleton-webpack-plugin')

const path = require('path')

plugins: [

//...

new HtmlWebpackPlugin({

// Your HtmlWebpackPlugin config

}),

new SkeletonPlugin({

pathname: path.resolve(__dirname, `${customPath}`), // 用来存储 shell 文件的地址

staticDir: path.resolve(__dirname, './dist'), // 最好和 `output.path` 相同

routes: ['/', '/search'], // 将需要生成骨架屏的路由添加到数组中

})

]

我们的实现方案

后来仔细想想,骨架屏这幅样子不是和一堆颜色块拼起来的页面一样吗?对比现有的骨架屏方案,这个想法有点“走捷径”的感觉。再进一步思考,这些色块基于当前页面去分析节点来生成,不如来段 JS 分析页面节点,一顿 DOM 操作生成颜色块拼成骨架屏。那么问题来了,该怎么样精确的分析页面节点,不同节点又该生成什么样的色块呢?

既然骨架屏代表了页面的大致结构,那么需要先用 js 对页面的结构进行分析。分析之前,我们需要制定一种规则,以确定需要排除哪些节点?哪些种类的节点需要生成颜色块?生成的颜色块如何定位等等。我们初步定下的规则如下:

只遍历可见区域可见的 DOM 节点,包括:

非隐藏元素、宽高大于 0 的元素、非透明元素、内容不是空格的元素、位于浏览窗口可见区域内的元素等;

针对(背景)图片、文字、表单项、音频视频、Canvas、自定义特征的块等区域来生成颜色块;

页面节点使用的样式不可控,所以不可取 style 的尺寸相关的值,可通过 getBoundingClientRect 获取节点宽、高、距离视口距离的绝对值,计算出与当前设备的宽高对应的百分比作为颜色块的单位,来适配不同设备;

基于这套规则,我们开始生成骨架屏:

首先,确定一个 rootNode 作为入口节点,比如 document.body,同时方便以后扩展到生成页面内局部的骨架屏,由此入口进行递归遍历和筛选,初步排除不可见节点。

function isHideStyle(node) {

return getStyle(node, 'display') === 'none' ||

getStyle(node, 'visibility') === 'hidden' ||

getStyle(node, 'opacity') == 0 ||

node.hidden;

}

接下来判断元素特征,确定是否符合生成条件,对于符合条件的区域,”一视同仁”生成相应区域的颜色块。”一视同仁”即对于符合条件的区域不区分具体元素、不考虑结构层级、不考虑样式,统一根据该区域与视口的绝对距离值生成 div 的颜色块。之所以这样是因为生成的节点是扁平的,体积比较小,同时避免额外的读取样式表、通过抽离样式维持骨架屏的外观,这种统一生成的方式使得骨架屏的节点更可控。基于那上述“走捷径”的想法,该方法生成的骨架屏是由纯 DOM 颜色块拼成的。

生成颜色块的方法:

const blocks = [];

// width,height,top,left 都是算好的百分比

function drawBlock({width, height, top, left, zIndex = 9999999, background, radius} = {}) {

const styles = [

'position: fixed',

'z-index: '+ zIndex,

'top: '+ top +'%',

'left: '+ left +'%',

'width: '+ width +'%',

'height: '+ height +'%',

'background: '+ background

];

radius && radius != '0px' && styles.push('border-radius: ' + radius);

// animation && styles.push('animation: ' + animation);

blocks.push(`

}

绘制颜色块并不难,绘制之前的分析确认才是这个方案真正的核心和难点。比如,对于页面结构比较复杂或者大图片比较多的页面,由图片拼接的区域没有边界,生成的颜色块就会紧挨着,出现不尽如人意的地方。再比如,一个包含很多符合生成条件的小块的 card 块区域,是以 card 块为准还是以里面的小块为准来生成颜色块呢?如果以小块为准,绘制结果可能给人的感觉压根就不是一个 card 块,再加上布局方式和样式的可能性太多,大大增加了不确定因素。而如果以 card 块为准生成颜色块的话还要对 card 块做专门的规则。

目前来说,对于页面结构不是特别复杂,不是满屏图片的,不是布局方式特别“飘逸“的场景,该方式已经可以生成比较理想的骨架屏了。而对于那些与预期相差较远的情况,我们提供了两个钩子函数可供微调:

init 函数,在开始遍历节点之前执行,适合删除干扰节点等操作。

includeElement(node, draw) 函数,可在遍历到指定节点时,调 用 draw 方法进行自定义绘制。

通过以上步骤就能够直接在浏览器中生成骨架屏代码了。

在浏览器里运行

由于我们的方案出发点是通过单纯的 DOM 操作,遍历页面上的节点,根据制定的规则生成相应区域的颜色块,最终形成页面的骨架屏,所以核心代码完全可以直接跑在浏览器端;

const createSkeletonHTML = require('draw-page-structure/evalDOM')

createSkeletonHTML({

// ...

background: 'red',

animation: 'opacity 1s linear infinite;'

}).then(skeletonHTML => {

console.log(skeletonHTML)

}).catch(e => {

console.error(e)

})

结合 Puppeteer 自动生成骨架屏

虽然该方式已经可以生成骨架屏代码了,但是还是不够自动化,为了让生成的骨架屏代码自动加载进指定页面。于是,我们开发了一个配套的 CLI 工具。这个工具通过 Puppeteer 运行页面,并把 evalDOM.js 脚本注入页面自动执行,执行的结果是生成的骨架屏代码被插入到应用页面。

我们的方案大概思路如下:

接下来看看如何使用 CLI 工具生成骨架屏,最多只需如下四步:

全局安装,npm i draw-page-structure – g

dps init 生成配置文件 dps.config.js

修改 dps.config.js 进行相关配置

dps start 开始生成骨架屏

只需简单几步,然而并没有繁琐的配置:

一般来说,你需要按自己的项目情况来配置 dps.config.js ,常见的配置项有:

url: 待生成骨架屏的页面地址

output.filepath: 生成的骨架屏节点写入的文件

output.injectSelector: 骨架屏节点插入的位置,默认 #app

background: 骨架屏主题色

animation: css3 动画属性

rootNode: 真对某个模块生成骨架屏

device: 设备类型,默认 mobile

extraHTTPHeaders: 添加请求头

init: 开始生成之前的操作

includeElement(node, draw): 定制某个节点如何生成

writePageStructure(html, filepath): 回调的骨架屏节点

详细代码及工具的使用请移步 Github;

初步实现的效果:

京东 PLUS 会员正式中首页:

京东 PLUS 会员正式中首页,通过该方案生成的骨架屏效果:

移动端百度首页:

移动端百度首页,通过该方案生成的骨架屏效果:

总结

以上就是基于 DOM 的骨架屏自动生成方案,其核心是 evalDOM 函数。这个方案在很多场景下的表现还是令人满意的。不过,网页布局和样式组合的可能性太多,想要在各种场景下都获得理想的效果,还有很长的路要走,但既然已经在路上,就勇敢的向前吧!

欢迎 star,欢迎提 PR !Github

react骨架屏自动生成_网页骨架屏自动生成方案(dps)相关推荐

  1. js生成图片_网页骨架屏自动生成方案(dps)

    来源:花满楼 https://zhuanlan.zhihu.com/p/74403911 什么是骨架屏? 什么是骨架屏呢?骨架屏(Skeleton Screen)是指在页面数据加载完成前,先给用户展示 ...

  2. react骨架屏自动生成_前端骨架屏方案小结

    骨架屏 最近在项目不时有用到骨架屏的需求,所以抽时间对骨架屏的方案作了一下调研,骨架屏的实践已经有很多了,也有很多人对自己的方案作了介绍.在这里按照个人的理解做了一个汇总和分类,分享给大家. 关于骨架 ...

  3. eladmin代码自动生成_如何让 Mybatis 自动生成代码

    1 创建代码生成器 1.1 创建Maven项目 1.2 配置 generator.xml 1.3 配置 pom.xml 1.4 使用及测试 2 XML 配置详解 2.1 优先 2.2 官网没有的 &l ...

  4. eladmin代码自动生成_如何让Mybatis自动生成代码

    点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 作者:阿进的写字台 cnblogs.com/homejim/p/9782403.html ...

  5. 乐播投屏总是自动断开_人人视频投屏连接失败_不能投屏电视解决办法_3DM手游...

    不少小伙伴在使用人人视频APP看视频的时候,都会用到其中的投屏功能.但是有时投屏的过程中会出现连接失败,不能投屏的情况,这该怎么办呢?下面我们一起来看看人人视频无法投屏电视的解决办法. 人人视频无法投 ...

  6. dseo13b打开自动消失_抖音怎么自动生成字幕?动态字幕有哪几种?

    点击蓝字关注,回复2 添加助教领取抖音资料大礼包 这是小星学长的第 96期分享 作者 l 小星学长 来源 l 星域赋能站(ID:gh_5663b69c0daa) 现在使用玩抖音短视频的新人是越来越多了 ...

  7. captura录屏没声音_电脑录屏有哪些好用的软件呢?

    嗨~大家好! 应粉丝要求,今天介绍一下电脑录屏软件,其实需要电脑录屏的需求大概率就那么几个: 1.游戏录播及后期制作. 2.课程录屏后方便再次学习. 3.动作演示,阁主就经常会通过录屏来演示某个软件怎 ...

  8. 电脑开机一会就蓝屏怎么回事_电脑蓝屏怎么回事

    电脑在使用的过程中,突然蓝屏.电脑不定时的自动重新启动.这种情况,可以进入系统查看蓝屏日志,进行蓝屏原因分析. 蓝屏日志文件位置: 蓝屏分析软件: 下载蓝屏分析软件 Debugging Tools f ...

  9. 手机息屏后停止_手机息屏还能这样玩?华为这几个隐藏小功能快学起来

    阅读本文前,请您先点击上面的"蓝色字体",再点击"关注",这样您就可以继续免费收到文章了.每天都有分享,完全是免费订阅,请放心关注. 注:本文转载自网络,如有侵 ...

  10. 苹果6换屏多钱_手机换屏维修的猫腻,附换屏须知

    手机维修最常见的维修项目就是手机屏幕的维修,很多人都有手机屏幕碎屏的经历,碎得心疼,换屏如滴血,少则几百,动辄几千,特别是iPhone手机,有些碎屏了依旧使用而不去换个屏幕. 然而,你可知道大多数换屏 ...

最新文章

  1. 知识图谱的皇冠:知识图谱推理的前世今生
  2. Java学习笔记--StringTokenizer的使用
  3. [latex]图片动态缩放的PDF动画示例
  4. duration转为时间戳_Flink Table APIamp;SQL编程指南之时间属性(3)
  5. qq互联开放平台 开源SDK共享 常见问题
  6. oracle 存储过程 胡勇,Oracle SQL:经典查询练手第二篇
  7. nftables-howto-zh中文手册(不完整)
  8. 脚本升级openssh
  9. SECS/GEM概念
  10. 史上最详细的MySQL数据库安装教程(图文详解)
  11. Windows Hello 摄像头人脸识别解锁 DELL拆机摄像头方案
  12. 可充电点电池和不可充电电池区分?
  13. android充电线排序,安卓数据线分类有哪些
  14. python四种方法求最大公约数(枚举法,辗转相除法,更相减损术,短除法)
  15. Java实现 蓝桥杯 算法提高 三进制数位和
  16. opengl 知识点2
  17. 相对路径、绝对路径写法
  18. Forest - 轻量级HTTP客户端框架
  19. 网络聊天中的英语简写
  20. 图像像素类型转换与归一化

热门文章

  1. think in java interview-高级开发人员面试宝典(十)
  2. 理解直播及其工作原理
  3. python中的translate函数_Python:内置函数makestrans()、translate()
  4. 阿里云OSS上传图片、PDF设置链接预览
  5. java列举生活中类和对象_趣味解读Python面向对象编程 (类和对象)
  6. 百度没有柳传志,联想没有李彦宏
  7. 【学习笔记】空间统计(常用)
  8. 获取当前时间,包括农历时间
  9. linux服务器如何查看硬盘型号,Linux如何查看硬盘型号和缓存
  10. 如何处理J-Link不能连接目标MCU的问题?