用純 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 !

相關文章
相關標籤/搜索