后来仔细想想,骨架屏这幅样子不是和一堆颜色块拼起来的页面一样吗?对比现有的骨架屏方案,这个想法有点“走捷径”的感觉。再进一步思考,这些色块基于当前页面去分析节点来生成,不如来段 JS 分析页面节点,一顿 DOM 操作生成颜色块拼成骨架屏。那么问题来了,该怎么样精确的分析页面节点,不同节点又该生成什么样的色块呢?
既然骨架屏代表了页面的大致结构,那么需要先用 js 对页面的结构进行分析。分析之前,我们需要制定一种规则,以确定需要排除哪些节点?哪些种类的节点需要生成颜色块?生成的颜色块如何定位等等。我们初步定下的规则如下:
1. 只遍历可见区域可见的 DOM 节点,包括:
非隐藏元素、宽高大于 0 的元素、非透明元素、内容不是空格的元素、位于浏览窗口可见区域内的元素等;
2. 针对(背景)图片、文字、表单项、音频视频、Canvas、自定义特征的块等区域来生成颜色块;
3. 页面节点使用的样式不可控,所以不可取 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 颜色块拼成的。
生成颜色块的方法:
c