mirror of
https://gitee.com/ulthon/ulthon_information.git
synced 2026-07-10 04:22:48 +08:00
feat(phone-image): code blocks converted to images via prismjs + html2canvas
This commit is contained in:
@@ -621,6 +621,75 @@ var PhoneImageEngine = (function () {
|
|||||||
|
|
||||||
// ===== DOM渲染 =====
|
// ===== DOM渲染 =====
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 #render-staging 中的代码块转为图片
|
||||||
|
* 使用 prismjs 高亮 + html2canvas 截图替换
|
||||||
|
* @returns {jQuery Deferred} resolves when all code blocks are converted
|
||||||
|
*/
|
||||||
|
function convertCodeBlocks() {
|
||||||
|
var deferred = $.Deferred();
|
||||||
|
var $staging = $('#render-staging');
|
||||||
|
|
||||||
|
// 检查 Prism 是否可用
|
||||||
|
if (typeof Prism === 'undefined') {
|
||||||
|
deferred.resolve();
|
||||||
|
return deferred.promise();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 给没有语言类的代码块添加默认语言
|
||||||
|
$staging.find('pre > code:not([class*="language-"])').addClass('language-plaintext');
|
||||||
|
|
||||||
|
// 高亮所有代码块
|
||||||
|
$staging.find('pre code').each(function () {
|
||||||
|
Prism.highlightElement(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 找到所有代码块,逐个截图替换
|
||||||
|
var $preBlocks = $staging.find('pre');
|
||||||
|
if ($preBlocks.length === 0) {
|
||||||
|
deferred.resolve();
|
||||||
|
return deferred.promise();
|
||||||
|
}
|
||||||
|
|
||||||
|
var idx = 0;
|
||||||
|
var total = $preBlocks.length;
|
||||||
|
|
||||||
|
function convertNext() {
|
||||||
|
if (idx >= total) {
|
||||||
|
deferred.resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var $pre = $preBlocks.eq(idx);
|
||||||
|
html2canvas($pre[0], {
|
||||||
|
scale: 2,
|
||||||
|
useCORS: true,
|
||||||
|
backgroundColor: '#f5f5f5',
|
||||||
|
logging: false
|
||||||
|
}).then(function (canvas) {
|
||||||
|
var imgData = canvas.toDataURL('image/jpeg', 0.92);
|
||||||
|
var $img = $('<img>');
|
||||||
|
$img.attr('src', imgData);
|
||||||
|
$img.css({
|
||||||
|
maxWidth: '100%',
|
||||||
|
height: 'auto',
|
||||||
|
display: 'block',
|
||||||
|
margin: '10px 0'
|
||||||
|
});
|
||||||
|
$pre.replaceWith($img);
|
||||||
|
idx++;
|
||||||
|
convertNext();
|
||||||
|
}).catch(function () {
|
||||||
|
// 截图失败则保留原始代码块
|
||||||
|
idx++;
|
||||||
|
convertNext();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
convertNext();
|
||||||
|
return deferred.promise();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 渲染到隐藏区域 → 截图 → 显示缩略图
|
* 渲染到隐藏区域 → 截图 → 显示缩略图
|
||||||
* @param {Object} sizeConfig
|
* @param {Object} sizeConfig
|
||||||
@@ -640,44 +709,86 @@ var PhoneImageEngine = (function () {
|
|||||||
|
|
||||||
// 等待一帧确保 DOM 渲染完成
|
// 等待一帧确保 DOM 渲染完成
|
||||||
requestAnimationFrame(function () {
|
requestAnimationFrame(function () {
|
||||||
var $pageElems = $staging.find('.phone-image-page');
|
// 先转换代码块为图片
|
||||||
if ($pageElems.length === 0) {
|
convertCodeBlocks().then(function () {
|
||||||
displayThumbnails([], sizeConfig);
|
var $pageElems = $staging.find('.phone-image-page');
|
||||||
deferred.resolve(pages);
|
if ($pageElems.length === 0) {
|
||||||
return;
|
displayThumbnails([], sizeConfig);
|
||||||
}
|
|
||||||
|
|
||||||
// 串行截图每一页
|
|
||||||
var thumbnailDataUrls = [];
|
|
||||||
var idx = 0;
|
|
||||||
var total = $pageElems.length;
|
|
||||||
|
|
||||||
function captureNext() {
|
|
||||||
if (idx >= total) {
|
|
||||||
$staging.empty();
|
|
||||||
displayThumbnails(thumbnailDataUrls, sizeConfig);
|
|
||||||
deferred.resolve(pages);
|
deferred.resolve(pages);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var $elem = $pageElems.eq(idx);
|
// 串行截图每一页
|
||||||
html2canvas($elem[0], {
|
var thumbnailDataUrls = [];
|
||||||
scale: 1,
|
var idx = 0;
|
||||||
useCORS: true,
|
var total = $pageElems.length;
|
||||||
backgroundColor: '#ffffff',
|
|
||||||
width: $elem.outerWidth(),
|
|
||||||
height: $elem.outerHeight(),
|
|
||||||
logging: false
|
|
||||||
}).then(function (canvas) {
|
|
||||||
thumbnailDataUrls.push(canvas.toDataURL('image/jpeg', 0.85));
|
|
||||||
idx++;
|
|
||||||
captureNext();
|
|
||||||
}).catch(function (err) {
|
|
||||||
deferred.reject('截图失败(第' + (idx + 1) + '页): ' + err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
captureNext();
|
function captureNext() {
|
||||||
|
if (idx >= total) {
|
||||||
|
$staging.empty();
|
||||||
|
displayThumbnails(thumbnailDataUrls, sizeConfig);
|
||||||
|
deferred.resolve(pages);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var $elem = $pageElems.eq(idx);
|
||||||
|
html2canvas($elem[0], {
|
||||||
|
scale: 1,
|
||||||
|
useCORS: true,
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
width: $elem.outerWidth(),
|
||||||
|
height: $elem.outerHeight(),
|
||||||
|
logging: false
|
||||||
|
}).then(function (canvas) {
|
||||||
|
thumbnailDataUrls.push(canvas.toDataURL('image/jpeg', 0.85));
|
||||||
|
idx++;
|
||||||
|
captureNext();
|
||||||
|
}).catch(function (err) {
|
||||||
|
deferred.reject('截图失败(第' + (idx + 1) + '页): ' + err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
captureNext();
|
||||||
|
}).catch(function () {
|
||||||
|
// 代码块转换失败,继续截图流程
|
||||||
|
var $pageElems = $staging.find('.phone-image-page');
|
||||||
|
if ($pageElems.length === 0) {
|
||||||
|
displayThumbnails([], sizeConfig);
|
||||||
|
deferred.resolve(pages);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var thumbnailDataUrls = [];
|
||||||
|
var idx = 0;
|
||||||
|
var total = $pageElems.length;
|
||||||
|
|
||||||
|
function captureNext() {
|
||||||
|
if (idx >= total) {
|
||||||
|
$staging.empty();
|
||||||
|
displayThumbnails(thumbnailDataUrls, sizeConfig);
|
||||||
|
deferred.resolve(pages);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var $elem = $pageElems.eq(idx);
|
||||||
|
html2canvas($elem[0], {
|
||||||
|
scale: 1,
|
||||||
|
useCORS: true,
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
width: $elem.outerWidth(),
|
||||||
|
height: $elem.outerHeight(),
|
||||||
|
logging: false
|
||||||
|
}).then(function (canvas) {
|
||||||
|
thumbnailDataUrls.push(canvas.toDataURL('image/jpeg', 0.85));
|
||||||
|
idx++;
|
||||||
|
captureNext();
|
||||||
|
}).catch(function (err) {
|
||||||
|
deferred.reject('截图失败(第' + (idx + 1) + '页): ' + err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
captureNext();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return deferred.promise();
|
return deferred.promise();
|
||||||
@@ -750,40 +861,79 @@ var PhoneImageEngine = (function () {
|
|||||||
$staging.append($wrapper);
|
$staging.append($wrapper);
|
||||||
|
|
||||||
requestAnimationFrame(function () {
|
requestAnimationFrame(function () {
|
||||||
var $pageElems = $staging.find('.phone-image-page');
|
// 先转换代码块为图片
|
||||||
if ($pageElems.length === 0) {
|
convertCodeBlocks().then(function () {
|
||||||
deferred.reject('没有可渲染的页面');
|
var $pageElems = $staging.find('.phone-image-page');
|
||||||
return;
|
if ($pageElems.length === 0) {
|
||||||
}
|
deferred.reject('没有可渲染的页面');
|
||||||
|
|
||||||
var canvases = [];
|
|
||||||
var idx = 0;
|
|
||||||
var total = $pageElems.length;
|
|
||||||
|
|
||||||
function captureNext() {
|
|
||||||
if (idx >= total) {
|
|
||||||
$staging.empty();
|
|
||||||
deferred.resolve(canvases);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
html2canvas($pageElems.eq(idx)[0], {
|
var canvases = [];
|
||||||
scale: 2,
|
var idx = 0;
|
||||||
useCORS: true,
|
var total = $pageElems.length;
|
||||||
backgroundColor: '#ffffff',
|
|
||||||
width: $pageElems.eq(idx).outerWidth(),
|
|
||||||
height: $pageElems.eq(idx).outerHeight(),
|
|
||||||
logging: false
|
|
||||||
}).then(function (canvas) {
|
|
||||||
canvases.push(canvas);
|
|
||||||
idx++;
|
|
||||||
captureNext();
|
|
||||||
}).catch(function (err) {
|
|
||||||
deferred.reject('截图失败(第' + (idx + 1) + '页): ' + err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
captureNext();
|
function captureNext() {
|
||||||
|
if (idx >= total) {
|
||||||
|
$staging.empty();
|
||||||
|
deferred.resolve(canvases);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
html2canvas($pageElems.eq(idx)[0], {
|
||||||
|
scale: 2,
|
||||||
|
useCORS: true,
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
width: $pageElems.eq(idx).outerWidth(),
|
||||||
|
height: $pageElems.eq(idx).outerHeight(),
|
||||||
|
logging: false
|
||||||
|
}).then(function (canvas) {
|
||||||
|
canvases.push(canvas);
|
||||||
|
idx++;
|
||||||
|
captureNext();
|
||||||
|
}).catch(function (err) {
|
||||||
|
deferred.reject('截图失败(第' + (idx + 1) + '页): ' + err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
captureNext();
|
||||||
|
}).catch(function () {
|
||||||
|
// 代码块转换失败,继续截图流程
|
||||||
|
var $pageElems = $staging.find('.phone-image-page');
|
||||||
|
if ($pageElems.length === 0) {
|
||||||
|
deferred.reject('没有可渲染的页面');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var canvases = [];
|
||||||
|
var idx = 0;
|
||||||
|
var total = $pageElems.length;
|
||||||
|
|
||||||
|
function captureNext() {
|
||||||
|
if (idx >= total) {
|
||||||
|
$staging.empty();
|
||||||
|
deferred.resolve(canvases);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
html2canvas($pageElems.eq(idx)[0], {
|
||||||
|
scale: 2,
|
||||||
|
useCORS: true,
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
width: $pageElems.eq(idx).outerWidth(),
|
||||||
|
height: $pageElems.eq(idx).outerHeight(),
|
||||||
|
logging: false
|
||||||
|
}).then(function (canvas) {
|
||||||
|
canvases.push(canvas);
|
||||||
|
idx++;
|
||||||
|
captureNext();
|
||||||
|
}).catch(function (err) {
|
||||||
|
deferred.reject('截图失败(第' + (idx + 1) + '页): ' + err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
captureNext();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return deferred.promise();
|
return deferred.promise();
|
||||||
|
|||||||
Reference in New Issue
Block a user