近ios15系統(tǒng)推出了,公司的app開(kāi)始測(cè)試ios15的兼容,然后就出現(xiàn)了有截圖的頁(yè)面卡頓白屏的問(wèn)題。
業(yè)務(wù)場(chǎng)景是這樣,我們的每個(gè)頁(yè)面都會(huì)有多個(gè)截圖,截圖使用的方式是html2canvas這個(gè)插件,
// 截圖方法
function convertToPoster() {
var $poster = $('#poster-content');
html2canvas($poster[0], {useCORS: true})
.then(
function (canvas) {
var oImage = new Image();
oImage.src = canvas.toDataURL('image/png', 1);
$(oImage)
.addClass('poster');
$poster.parent()
.after(oImage)
.hide();
}
);
};
$(window).load(function() {
convertToPoster();
})
當(dāng)頁(yè)面先截一張圖之后,再去截第二張圖時(shí),頁(yè)面就會(huì)出現(xiàn)卡頓白屏的問(wèn)題,這個(gè)問(wèn)題時(shí)必現(xiàn),且在ios的瀏覽器中走也是這樣。
經(jīng)過(guò)很多輪的調(diào)試之后,依然找不出原因,因?yàn)榧葻o(wú)報(bào)錯(cuò)也不確定頁(yè)面是在哪行代碼卡住的,最終只能采用笨辦法,去屏蔽頁(yè)面的html結(jié)構(gòu),只留下兩個(gè)截圖的結(jié)構(gòu),突然好運(yùn)降臨,頁(yè)面不卡了,截圖成功了,那是不是就能證明是頁(yè)面的某個(gè)dom結(jié)構(gòu)導(dǎo)致的呢?
因?yàn)轫?yè)面較為復(fù)雜,最終經(jīng)過(guò)10多輪的屏蔽組合,終于確定在了button這里,那么這個(gè)button按鈕的樣式會(huì)有什么影響呢?
一步一步挨個(gè)去屏蔽屬性,結(jié)果并沒(méi)有預(yù)料中的變好,正在疑惑之時(shí),突然看到了用戶(hù)代理樣式里面有三個(gè)屬性是沒(méi)有替換的,其中有個(gè)font-family:system-ui這個(gè)樣式在chrome瀏覽器中是沒(méi)有的,會(huì)不會(huì)是這個(gè)影響的呢?果然屏蔽了它之后就可以了,頁(yè)面操作無(wú)比絲滑。
我們先來(lái)看看這個(gè)樣式究竟是什么意思?
system-ui是一種通用字體系列,它選擇當(dāng)前操作系統(tǒng)下的默認(rèn)系統(tǒng)字體,它的優(yōu)勢(shì)在于和當(dāng)前系統(tǒng)使用的字體相匹配,可以讓W(xué)eb頁(yè)面和App風(fēng)格看起來(lái)更統(tǒng)一。
話(huà)說(shuō)它雖然出現(xiàn)得比較晚,但是在can i use上顯示的兼容性還是很好的,為啥會(huì)出現(xiàn)在ios15的手機(jī)系統(tǒng)上呢?目前ios15的資料還少之又少查不到,有待于深究。
記錄下目前的處理方案:
//兼容ios15手機(jī)系統(tǒng)字體導(dǎo)致的問(wèn)題
var isiOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios終端
if (isiOS) {
var ios_ver = parseInt(navigator.userAgent.toLowerCase().match(/cpu iphone os (.*?) like mac os/)[1].replace(/\_/g, '.'));
if (ios_ver >= 15) {
if ($('button')) {
$('button').css('font-family', 'PingFangSC-Regular');
}
}
}
版權(quán)聲明
本文為[青咕咕]所創(chuàng),轉(zhuǎn)載請(qǐng)帶上原文鏈接,感謝
https://juejin.im/post/7006119499216715783
尋找熱愛(ài)表達(dá)的你#
"一鍵將網(wǎng)頁(yè)截圖制作成HTML網(wǎng)頁(yè)"是指一種技術(shù),它允許用戶(hù)通過(guò)簡(jiǎn)單的操作,將網(wǎng)頁(yè)的截圖轉(zhuǎn)換成HTML代碼的網(wǎng)頁(yè)。這通常涉及到自動(dòng)布局、樣式提取和代碼生成。以下是實(shí)現(xiàn)這一功能的相關(guān)技術(shù)和步驟:
1. 截圖捕捉:首先,需要有一個(gè)方法來(lái)捕捉網(wǎng)頁(yè)的截圖,這可以通過(guò)瀏覽器插件、屏幕捕獲工具或?qū)iT(mén)的應(yīng)用程序來(lái)完成。
2. 圖像處理:捕捉到的截圖可能需要進(jìn)行預(yù)處理,比如裁剪、壓縮或調(diào)整分辨率,以確保圖像的質(zhì)量。
3. 元素識(shí)別:使用圖像識(shí)別技術(shù)來(lái)分析截圖,識(shí)別網(wǎng)頁(yè)中的元素,比如文本、按鈕、圖片等。
4. 布局分析:基于識(shí)別出的元素,分析頁(yè)面的布局信息,包括元素的大小、位置和層級(jí)。
5. 樣式解析:提取頁(yè)面的樣式信息,包括顏色、字體、間距等,并將它們轉(zhuǎn)換為CSS代碼。
6. HTML生成:根據(jù)布局和樣式信息,生成HTML結(jié)構(gòu)代碼,將截圖中的元素轉(zhuǎn)換為HTML標(biāo)簽。
7. 代碼優(yōu)化:對(duì)生成的HTML代碼進(jìn)行優(yōu)化,確保代碼的可讀性、維護(hù)性和性能。
8. 響應(yīng)式設(shè)計(jì):確保生成的網(wǎng)頁(yè)代碼能夠適應(yīng)不同的屏幕尺寸和設(shè)備,實(shí)現(xiàn)響應(yīng)式布局。
9. 交互性實(shí)現(xiàn):如果截圖中的頁(yè)面包含交互元素,需要添加相應(yīng)的JavaScript代碼來(lái)實(shí)現(xiàn)這些交互。
10. 一鍵操作:提供一個(gè)簡(jiǎn)單的用戶(hù)界面,用戶(hù)只需點(diǎn)擊一個(gè)按鈕,就可以完成截圖到HTML的轉(zhuǎn)換。
11. 預(yù)覽功能:在轉(zhuǎn)換過(guò)程中提供實(shí)時(shí)預(yù)覽,讓用戶(hù)可以實(shí)時(shí)看到轉(zhuǎn)換效果。
12. 自定義選項(xiàng):允許用戶(hù)對(duì)生成的HTML代碼進(jìn)行自定義,比如修改布局、添加額外的樣式或功能。
13. 保存和導(dǎo)出:用戶(hù)可以保存或?qū)С錾傻腍TML代碼,以便進(jìn)一步使用或分享。
14. 錯(cuò)誤處理:在轉(zhuǎn)換過(guò)程中識(shí)別和處理潛在的錯(cuò)誤,比如布局沖突或樣式問(wèn)題。
15. 兼容性測(cè)試:確保生成的網(wǎng)頁(yè)在不同的瀏覽器和設(shè)備上都能正常顯示和工作。
16. 安全性考慮:生成的代碼應(yīng)遵循安全最佳實(shí)踐,避免潛在的安全風(fēng)險(xiǎn)。
17. 用戶(hù)反饋:收集用戶(hù)反饋,不斷改進(jìn)轉(zhuǎn)換算法和用戶(hù)體驗(yàn)。
18. 開(kāi)源和社區(qū)支持:作為開(kāi)源項(xiàng)目,鼓勵(lì)社區(qū)參與貢獻(xiàn)代碼和改進(jìn)功能。
這種一鍵轉(zhuǎn)換技術(shù)可以大大提高網(wǎng)頁(yè)開(kāi)發(fā)的效率,尤其是對(duì)于快速原型設(shè)計(jì)和演示目的。然而,需要注意的是,自動(dòng)生成的代碼可能需要進(jìn)一步的人工審查和調(diào)整,以確保最終產(chǎn)品的質(zhì)量和性能。此外,一些復(fù)雜的網(wǎng)頁(yè)效果和動(dòng)態(tài)交互可能需要手動(dòng)編寫(xiě)代碼來(lái)實(shí)現(xiàn)。
需求一直有,今年比較多,如題,工作中遇到網(wǎng)頁(yè)截圖這樣的需求,本著效果好,功能全又穩(wěn)定的意圖,去網(wǎng)上搜索相關(guān)技術(shù),像HTML2Image、cssbox、selenium等,還有很多其他的技術(shù),這篇文章主要說(shuō)說(shuō)我測(cè)試使用并能滿(mǎn)足需求的cssbox,selenium。
CSSBox是一個(gè)用純Java編寫(xiě)的(X)HTML/CSS渲染引擎。它的主要目的是提供關(guān)于呈現(xiàn)的頁(yè)面內(nèi)容和布局的完整和進(jìn)一步可處理的信息。 但是,它也可以用于瀏覽Java Swing應(yīng)用程序中呈現(xiàn)的文檔。核心CSSBox庫(kù)還可以用于獲得所呈現(xiàn)的文檔的位圖或矢量(SVG)圖像。 使用SwingBox包,CSSBox可以用作Java Swing應(yīng)用程序中的交互式Web瀏覽器組件。
官網(wǎng)地址:http://cssbox.sourceforge.net/
<!--網(wǎng)站轉(zhuǎn)換為圖片cssbox-->
<dependency>
<groupId>net.sf.cssbox</groupId>
<artifactId>cssbox</artifactId>
<version>5.0.0</version>
</dependency>
@Test
public void cssboxTest(){
try {
ImageRenderer render = new ImageRenderer();
//網(wǎng)絡(luò)鏈接的html
String url = "https://www.zhangbj.com/p/524.html";
//文件保存路徑
String path = "C:\\Users\\Administrator\\Desktop"+File.separator+"html.png";
FileOutputStream out = new FileOutputStream(new File(FilenameUtils.normalize(path)));
//開(kāi)始截屏
render.renderURL(url, out);
} catch (Exception e) {
e.printStackTrace();
}
}
樣式可能出現(xiàn)問(wèn)題,中文有時(shí)候亂碼
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
selenium+chromedriver谷歌驅(qū)動(dòng)+chrome瀏覽器
1.注意谷歌驅(qū)動(dòng)的版本要和谷歌瀏覽器的版本一樣或者版本最相近
2.注意chromedriver谷歌驅(qū)動(dòng)需要放在jdk安裝目錄下,具體路徑為xxx/bin/chromedriver.exe,在linux和window中操作一樣,這樣切換系統(tǒng)是就無(wú)需改代碼。
3.需要安裝谷歌瀏覽器
谷歌驅(qū)動(dòng)下載地址:https://registry.npmmirror.com/binary.html?path=chromedriver/
@Slf4j
public class Html2ImageUtil {
/**
* 將HTML轉(zhuǎn)為圖片,并保存至指定位置
* @param url 頁(yè)面地址
* @param targetPath 保存地址(包含圖片名,如 /images/test.png)
* @return
*/
public static String htmlToImage(String url, String targetPath) {
if (StringUtils.isEmpty(url) || StringUtils.isEmpty(targetPath)) {
throw new RuntimeException("截圖失敗!缺少必填項(xiàng)");
}
// 休眠時(shí)長(zhǎng)
Integer sleepTime = 3 * 1000;
// 無(wú)頭模式
System.setProperty("java.awt.headless", "true");
//獲取谷歌配置信息
ChromeOptions chromeOptions = getChromeOptions();
// 配置信息中有默認(rèn)窗口大小,也可以單獨(dú)設(shè)置窗口大小
chromeOptions.addArguments("--window-size=1920,6000");
//創(chuàng)建webdriver 谷歌驅(qū)動(dòng)
WebDriver driver = new ChromeDriver(chromeOptions);
//也可以通過(guò)如下方式設(shè)置窗口大小
// Dimension dimension = new Dimension(1000, 30);
// driver.manage().window().setSize(dimension);
try {
//加載頁(yè)面
driver.get(url);
//等待加載頁(yè)面
Thread.sleep(sleepTime);
//截屏
File srcFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
//保存到指定位置
FileUtils.copyFile(srcFile, new File(FilenameUtils.normalize(targetPath)));
} catch (InterruptedException | IOException e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
} finally {
driver.quit();
}
log.info("截圖成功!");
return targetPath;
}
/**
* 獲取chrome配置信息
* 注意 chromedriver谷歌驅(qū)動(dòng)需要放在jdk安裝目錄下,具體路徑為xxx/bin/chromedriver.exe ,在linux和window中操作一樣
* @return
*/
public static ChromeOptions getChromeOptions() {
ChromeOptions options = new ChromeOptions();
//獲取當(dāng)前操作系統(tǒng)
String os = System.getProperty("os.name");
//獲取jdk安裝目錄,需要提前將谷歌驅(qū)動(dòng)放進(jìn)jdk的bin目錄下,在linux和window中操作一樣
String sysPath = System.getProperty("java.home").replace("jre", "bin");
String chromeDriver = sysPath + File.separator+"chromedriver.exe";
options.addArguments("disable-infobars");
//設(shè)置為 headless 模式,不需要真實(shí)啟動(dòng)瀏覽器
options.setHeadless(true);
//options.addArguments("--headless");
options.addArguments("--dns-prefetch-disable");
options.addArguments("--no-referrers");
options.addArguments("--disable-gpu");
options.addArguments("--disable-audio");
options.addArguments("--no-sandbox");
options.addArguments("--ignore-certificate-errors");
options.addArguments("--allow-insecure-localhost");
options.addArguments("--window-size=1920,6000"); // 窗口默認(rèn)大小
String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36";
userAgent = "user-agent=" + userAgent;
options.addArguments(userAgent);
// 設(shè)置chrome二進(jìn)制文件
options.setPageLoadStrategy(PageLoadStrategy.EAGER);
// 設(shè)置驅(qū)動(dòng)
System.setProperty("webdriver.chrome.driver", chromeDriver);
log.debug("結(jié)束獲取chrome配置信息");
return options;
}
public static void main(String[] args) {
htmlToImage("https://www.cnblogs.com/tester-ggf/p/12602211.html","C:\\Users\\Administrator\\Desktop\\aaa.png");
}
效果十分完美
最完美的方案就是selenium+chromedriver谷歌驅(qū)動(dòng)+chrome瀏覽器,無(wú)需多說(shuō),用吧。
您的贊和關(guān)注是對(duì)我創(chuàng)作的最大肯定謝謝大家!
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。