bia
Version:
a tool for download git repository
236 lines (214 loc) • 8.12 kB
JavaScript
const puppeteer = require('puppeteer')
const fse = require('fs-extra')
const path = require('path')
const SKELETON_CONFIG = require('../../config/skeleton.json')
/**
* 查询 skeleton config 文件是否存在
*/
const checkSkeletonFile = () => {
return new Promise((resolve, reject) => {
try {
let file = path.resolve(process.cwd(), 'biaSkeleton/config.json')
fse.exists(file, exists => {
resolve(exists)
})
} catch (err) {
reject(err)
}
})
}
/**
* 创建 skeleton config.json 文件
*/
const createSkeletonFile = (_config = {}) => {
return new Promise((resolve, reject) => {
try {
let dist = path.resolve(process.cwd(), 'biaSkeleton')
fse.ensureDirSync(dist)
fse.outputFileSync(path.resolve(dist, 'config.json'), JSON.stringify(Object.assign(SKELETON_CONFIG, _config), null, 4))
resolve()
} catch (err) {
reject(err)
}
})
}
/**
* 读取配置文件信息
*/
const readConfigFlile = () => {
return new Promise((resolve, reject) => {
try {
fse.readJson(path.resolve(process.cwd(), 'biaSkeleton/config.json'), (err, obj) => {
if (err) {
console.log('some error in config.json, Check the file format')
reject(err)
}
resolve(obj)
})
} catch (err) {
reject(err)
}
})
}
/*
* 启动puppeteer 生成骨架屏
*/
const outputSkeleton = async (config) => {
const browser = await puppeteer.launch({
headless: false
})
const page = await browser.newPage()
// 拦截请求
await page.setRequestInterception(true);
page.on('request', interceptedRequest => {
if (/\.png|\.jpg|\.jpeg|\.gif/.test(interceptedRequest.url())) {
interceptedRequest.abort()
} else {
interceptedRequest.continue()
}
})
// 设置cookie
config.cookies && config.cookies.forEach(item => {
page.setCookie(item)
})
await page.setUserAgent(config.viewport.userAgent)
// 设置视窗
await page.setViewport({
width: config.viewport.width || 375,
height: config.viewport.height || 812,
deviceScaleFactor: config.viewport.dpr || 2,
isMobile: true,
})
// 打开链接
await page.goto(config.url, {
waitUntil: 'networkidle2',
})
await page.content()
// 操作页面
await page.evaluate((config) => {
// 处理图片为灰色背景的方法
const formatImage = (query) => {
try {
Array.from(document.body.querySelectorAll(query)).forEach(node => {
node.hasAttribute('alt') && node.removeAttribute('alt')
node.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
node.style.backgroundColor = config.options.skeletonColor || '#eee'
node.style.backgroundImage = 'none'
const rect = node.getBoundingClientRect()
node.style.width = rect.width
node.style.height = rect.height
})
} catch (err) {
console.log(err)
//
}
}
// 处理文字为灰色背景的方法
const formatText = (query) => {
try {
Array.from(document.body.querySelectorAll(query)).forEach(node => {
if (node.innerText !== node.innerHTML) return false
const comStyle = window.getComputedStyle(node)
let {
lineHeight,
fontSize,
paddingTop,
paddingBottom,
} = comStyle
const height = node.offsetHeight
let lineCount = (height - parseInt(paddingTop, 10) - parseInt(paddingBottom, 10)) / parseInt(lineHeight, 10) | 0
lineCount = lineCount - 1 < 0 ? 0 : lineCount - 1
let textHeightRatio = parseInt(fontSize, 10) / parseInt(lineHeight, 10)
const innerWrapper = document.createElement('biaspan')
innerWrapper.innerText = node.innerText
Object.assign(innerWrapper.style, {
backgroundImage: `linear-gradient(
transparent ${(1 - textHeightRatio) / 2 * 100}%,
${config.options.skeletonColor || '#eee'} 0%,
${config.options.skeletonColor || '#eee'} ${((1 - textHeightRatio) / 2 + textHeightRatio) * 100}%,
transparent 0%)`,
backgroundOrigin: 'content-box',
backgroundSize: `100% ${parseFloat(lineHeight) * lineCount}px`,
backgroundClip: 'content-box',
backgroundColor: (lineCount ? 'transparent' : config.options.skeletonColor || '#eee'),
fontSize,
color: 'transparent',
backgroundRepeat: 'repeat-y',
display: 'inline',
})
node.innerHTML = ''
node.appendChild(innerWrapper)
})
} catch (err) {
console.log(err)
//
}
}
// 隐藏伪元素
let style = document.createElement('style')
document.head.appendChild(style)
sheet = style.sheet
sheet.insertRule('*::before { display: none; }', 0)
sheet.insertRule('*::after { display: none; }', 0)
// 设置页面背景色
document.body.style.background = config.options.bgColor || '#fff'
// 隐藏部分元素
if (config.options && config.options.hide) {
config.options.hide.forEach(node => {
Array.from(document.body.querySelectorAll(node)).forEach(subNode => {
subNode.style.display = 'none'
subNode.style.visibility = 'hidden'
})
})
}
// 所有元素全部变成透明,过滤ignore的元素
let ignoreNodeList = []
if (config.options && config.options.ignore) {
config.options.ignore.forEach(node => {
console.log(node)
ignoreNodeList = ignoreNodeList.concat(Array.from(document.body.querySelectorAll(node)))
})
}
Array.from(document.body.querySelectorAll('*')).forEach(node => {
if (!ignoreNodeList.includes(node)) {
node.style.color = 'transparent'
node.style.backgroundColor = 'transparent'
node.style.background = 'none'
node.style.border = 'none'
// 处理 input,textarea
node.placeholder = ''
node.value = ''
}
})
// 处理图片
formatImage('img')
// 处理自定义图片
if (config.options && config.options.img) {
config.options.img.forEach(subNode => {
formatImage(subNode, config)
})
}
// 处理文案
formatText('span, p')
// 处理自定义文案
if (config.options && config.options.text) {
config.options.text.forEach(subNode => {
formatText(subNode, config)
})
}
}, config)
// 截图
const distFolder = path.resolve(process.cwd(), 'biaSkeleton/result')
await fse.ensureDir(distFolder)
await page.screenshot({
path: path.resolve(distFolder, 'skeleton.png')
})
// await browser.close()
// process.exit()
}
module.exports = {
checkSkeletonFile,
createSkeletonFile,
readConfigFlile,
outputSkeleton,
}