在rrweb对html还原时,如果html中的操作是:快速跳了多个页面,将会出现有一些时间css丢失的情况,因为一些css资源是需要从服务器中请求的,如果加载时间不够将会出现css丢失
该问题不会影响一般的页面显示,但是如果我们需要对html中的div截图的话,将会造成较大影响
该问题算是 rrweb 的一个bug或是优化项,rrweb 没有做的话,我们需要先手动处理他的数据
解决方案
方案1:对需要请求服务器获取的 css 资源先进行预加载
加载 css 方法,先写一个获取css的方法,需要使用 http 模块,方法返回已加载 css 数据
const http = require('http');
const https = require('https');
function requestCSS(url) {
return new Promise((resolve, reject) => {
let protocol = null
if (url.includes("https")) {
protocol = https
} else if (url.includes("http")) {
protocol = http
} else {
reject('url error')
}
try {
protocol && protocol.get(url, (response) => {
let chunks = [];
let size = 0;
response.on('data', (chunk) => {
chunks.push(chunk);
size += chunk.length;
});
response.on('end', () => {
let data = Buffer.concat(chunks, size);
let base64Data = data.toString('utf-8');
resolve(base64Data);
});
}).on("error", (error) => {
console.log("Error: " + error.message);
reject(error)
});
} catch (error) {
console.log("url Error: " + error.message);
reject(error)
}
})
}
对 rrweb 数据使用正则匹配出需要从服务器获取的 css 标签数据,并调用加载方法对其加载,返回处理后的数据,需注意的是,可以对 css 的注释进行过滤
function preloadCSS(eventsJson) {
return new Promise(async (resolve) => {
let cssHrefObj = [];
let cssHref = eventsJson.match(/link(.)+?\}/g);
if (cssHref) {
cssHref.forEach(item => {
let res = item.match(/(?<=attributes\"\:).*/g);
if (res) { cssHrefObj.push(...res) }
})
}
for (let i = 0; i < cssHrefObj.length; i++) {
let url = cssHrefObj[i].match(/(?<=href\"\:\").*?(?=\")/g)
if (url) {
try {
let res = await requestCSS(url[0]);
console.log(res)
// res = JSON.stringify(res).replace(/\/\*.+?\*\//g, "")
eventsJson = eventsJson.replace(cssHrefObj[i], '{"_cssText": ' + JSON.stringify(res) + '}');
} catch (err) {
console.log(err);
}
}
}
resolve(eventsJson)
})
}
方案2:如果需要对div截图,在截图之前预留更多的时间给html页面加载css
通过时间戳识别出,页面跳转前的时间,一旦匹配到页面需要跳转时,预留更多的时间留给css加载
(async () => {
let delay = 500
await new Promise((resolve) => {
setTimeout(() => { resolve() }, delay)
})
const buffer = await this.wrapperEl.screenshot({
encoding: "binary",
});
})()
可以从rrweb的原始数据中获取到页面的时间戳,在时间戳前面,通过await做延时执行,延时500毫秒(css从服务器中加载时间大约在200-250ms)