骨架屏是在頁面數據還沒有加載完成前先給用戶展現出頁面的大體結構, 解決了js加載時間過長頁面白頁的問題,同時,相對於loading動畫,骨架屏的過渡效果更加平滑,用戶體驗更好。 骨架屏能夠由開發人員手動編寫,這篇文章中咱們使用chrome推出的Node庫puppeteer,自動爲頁面生成相應的骨架屏。javascript
這篇文章主要分爲如下幾點html
Puppeteer 是一個 Node 庫,它提供了一個高級 API 來經過 DevTools 協議控制 Chromium 或 Chrome。Puppeteer 默認以 headless 模式運行,可是能夠經過修改配置文件運行「有頭」模式。vue
puppeteer能夠經過node自動打開瀏覽器,而且在真實的瀏覽器環境中執行代碼,所以能夠應用於自動化黑盒測試等場景。 咱們此次用puppeteer打開指定頁面而且操做dom,從而獲得真實頁面的骨架屏版本截圖。java
對puppeteer想要有更多瞭解的同窗能夠訪問node
在項目中使用puppeteer很簡單,可是因爲一些網絡緣由,在國內直接npm安裝會沒法獲取Chromium報錯。webpack
網上廣泛的解決方案是在安裝puppeteer的時候跳過Chromium,再去Chromium官網下載最新版本Chromium,最後在使用的時候修改Chromiumd的引用路徑。git
更好的方法是經過淘寶鏡像cnpm安裝puppeteer,親測可用,而且速度驚人:github
cnpm install -g puppeteer
複製代碼
puppeteer中文API文檔中有不少demo,咱們這裏主要使用了puppeteer的 Browser對象和 Page對象,Browser用於操做瀏覽器對象,page用於操做document對象web
如下爲puppeteer使用的基本語法:chrome
var skelentonOptions = {
url:'http://localhost:8081',
width:375,
height:667
};
async function getSkeleton(option = {}){
//建立指定尺寸的瀏覽器窗口
const browser = await puppeteer.launch({headless:true,defaultViewport:{width:option.width, height:option.height}});
//新建tab頁
const page = await browser.newPage();
//打開頁面 指定路徑
await page.goto(option.url,{waitUntil: 'networkidle0'});
//具體邏輯
//...
// 截屏首頁
await page.screenshot({
path: 'ske.png',
type: 'png',
clip:{
x:0,
y:0,
width:option.width,
height:option.height
}
})
//關閉虛擬chrome
await browser.close();
}
getSkeleton(skelentonOptions);
複製代碼
個人替換思路是頁面加載後,找到文字和圖片,文字部分替換顏色和背景色爲灰色,圖片部分用一張默認圖代替,dom其餘的部分隱藏。
下面是修改dom部分的代碼:
var body = document.getElementsByTagName('body')[0],
spanList = Array.from(document.getElementsByTagName('span')),
pList = Array.from(document.getElementsByTagName('p')),
h1List = Array.from(document.getElementsByTagName('h1')),
h2List = Array.from(document.getElementsByTagName('h2')),
h3List = Array.from(document.getElementsByTagName('h3')),
h4List = Array.from(document.getElementsByTagName('h4')),
h5List = Array.from(document.getElementsByTagName('h5')),
h6List = Array.from(document.getElementsByTagName('h6')),
spanLen = spanList.length,
pLen = pList.length,
h1Len = h1List.length,
h2Len = h2List.length,
h3Len = h3List.length,
h4Len = h4List.length,
h5Len = h5List.length,
h6Len = h6List.length,
imgList = document.getElementsByTagName('img'),
imgLen = imgList.length;
// 隱藏其餘元素
body.style.visibility = 'hidden';
// 修改字體樣式
var textList = spanList.concat(pList, h1List, h2List, h3List, h4List, h5List, h6List),
textLen = spanLen + pLen + h1Len + h2Len + h3Len + h4Len + h5Len + h6Len;
for(let i = 0;i < textLen;i++){
textList[i].style.color = '#eee';
textList[i].style.backgroundColor = '#eee';
textList[i].style.visibility = 'visible';
}
// 修改圖片樣式
for(let i = 0;i<imgLen;i++){
imgList[i].src = 'http://image1.51tiangou.com/tgou2/img/bg-load.png';
imgList[i].style.backgroundColor = '#eee';
imgList[i].style.visibility = 'visible';
}
複製代碼
dom幾點修改完畢以後,使用puppeteer的截屏功能,獲得指定大小的首頁骨架屏圖片一張。
vue項目的入口文件index.html只有很簡單的結構
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>carry_cli_test</title>
</head>
<body>
<noscript>
<strong>We're sorry but carry_cli_test doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app">
</div>
<!-- built files will be auto injected -->
</body>
</html>
複製代碼
當js執行完以後,會用vue渲染成的dom將div#app 徹底替換掉
所以,咱們把骨架屏圖片放在div#app中
下面看一下效果
兩者都是webpack插件。
vue-skeleton-webpack-plugin使用了服務端渲染的原理 vue-skeleton-webpack-plugin的使用 page-skeleton-webpack-plugin是餓了麼團隊開發的,原理與本文相似,感興趣的同窗能夠看下這篇教程 自動化生成 H5 骨架頁面