用纯 DOM 的方式结合 Puppeteer 自动生成网页骨架屏

  骨架屏是在页面数据还没有加载完成前先给用户展现出页面的大体结构,直到请求数据返回后再显示真正的页面内容;随着单页应用( SPA )的愈来愈流行,单页应用的用户体验也愈来愈获得前端开发者的关注;为了优化用户体验,在数据到达用户以前,每每会在页面上加上 loading 的效果,而如今,愈来愈多的场景倾向于使用页面的骨架替代单一的 loading 效果;javascript

为何须要自动生成骨架屏?css

  1. 提升效率,节约单独编写骨架屏代码的时间
  2. 替换原来单一的 loading 图片效果
  3. 能够优化用户体验,在页面数据还没有加载完成前先给用户展现出页面的大体结构,配合动画效果,给用户一种平滑切换的感受

常见的方案:前端

  1. 手动编写骨架屏代码
  2. 经过预渲染手动书写的代码生成相应的骨架屏 好比:vue-skeleton-webpack-plugin
  3. 饿了么内部的生成骨架页面的工具 page-skeleton-webpack-plugin
  4. ..

a. 前二者的前提都是须要开发者本身编写骨架屏代码vue

b. 饿了么的作的比较强大了,还有 UI 界面专门调整骨架屏java

  • 对于复杂的页面也会有不尽如人意的地方
  • 生成的骨架屏节点是基于页面自己的结构和 CSS,存在嵌套比较深的状况,体积不会过小
  • 只支持 history 模式.

咱们的方案是:用纯 DOM 的方式结合 Puppeteer 自动生成网页骨架屏node

  • 编写操做 DOM 的 Javascript 脚本
    • 遍历可见区域可见的 DOM 节点 包括:非隐藏元素、宽高大于 0 的元素、非透明元素、内容不是空格的元素、位于浏览窗口可见区域内的元素
    • 针对(背景)图片、文字、表单项、音频视频等区域,算出其所占区域的宽、高、距离视口的绝对距离等信息
    • 对于符合生成条件的区域,一视同仁,生成相应区域的颜色块
    • “一视同仁”即对于符合条件的区域,不区分具体元素,不用考虑结构层级,不考虑样式,统一辈子成 div 的颜色块
    • 该脚本的运行环境决定了获取到的元素尺寸与相关距离单位不可控,可能须要作转换,好比用的 rem、em、vh 等;咱们采用比较简单的方式,不取 style 的尺寸相关的值,而是经过 getBoundingClientRect 获取宽、高、距离视口距离的绝对值,与当前设备的宽高,计算出相应的百分比做为颜色块的单位,这样来适配不一样设备
    • 对于页面结构比较复杂或者大图片比较多的页面,会出现不尽如人意的地方,咱们经过 includeElement(node, draw)和 init 两个钩子函数来支持自定义的微调
    • 以上就可以直接跑在浏览器生成骨架屏代码了,手动添加到应用页面
const createSkeletonHTML = require('DrawPageStructure/evalDOM')

    createSkeletonHTML({
        // ...
        background: 'red',
        animation: 'opacity 1s linear infinite;'
    }).then(skeletonHTML => {
        console.log(skeletonHTML)
    }).catch(e => {
        console.error(e)
    })
复制代码

  直接在浏览器端运行,在控制台打印当前页面骨架屏节点,复制添加到应用页面,可是该方式不够自动化,咱们该让骨架屏自动生成并添加到应用页面react

  • Puppeteer

Puppeteer 是谷歌官方出品的一个能够控制 headless Chrome 的 Node 库。能够经过 Puppeteer 的提供的 api 直接控制 Chrome 模拟大部分用户操做来进行 UI Test 或者做为爬虫访问页面来收集数据。webpack

Puppeteer 提供运行环境和导出方式git

  1. 使用 puppeteer 运行须要生成骨架屏的页面
  2. 将以前编写的 Javascript 脚本经过 puppeteer 提早注入到该页面,这样便可运行该脚本,并生成骨架屏所需的 DOM 节点
  3. 将自动生成的骨架屏 DOM 片断插入到应用页面的入口节点
const evalDOM = require('../evalDOM');

await page.goto(url, {waitUntil: 'networkidle0'});
const skeletonHTML = await page.evaluate.call(page, evalDOM, ...args);
复制代码

小结github

  1. 核心在于 DOM 操做,puppeteer 仅提供运行环境和导出方式
  2. 只要能访问的页面都能生成,history 与 hash 模式无限制
  3. 不受项目和框架的限制,vue 和 react 等项目零修改便可复用
  4. 生成色块的单位为百分比,不一样设备自适应
  5. 不须要 css-tree 来提取样式,不依赖页面自己的布局结构,生成扁平的 DOM 节点体积特别小
  6. 支持自定义生成方式与导出方式

还有不少细节优化中,欢迎感兴趣的小伙伴一块儿加入!

详细代码和使用方式请移步: github.com/famanoder/D…

欢迎 star !,欢迎提 PR !

相关文章
相关标签/搜索