mirror of
https://gitee.com/ulthon/ulthon_information.git
synced 2026-07-01 18:32:48 +08:00
refactor(phone-image): 在中间栏截图转换表格和代码块为图片,确保渲染一致性
- 新增 convertFlowBlocksToImages():在 #content-flow 中用 html2canvas 截图转换 table/pre 块为 img - 修改 render() 管线:renderContentFlow -> convertFlowBlocksToImages -> measureBlockHeights - 删除旧的 convertCodeBlocks() 和 convertTables()(doCapturePages 中不再需要) - 添加 parseHtmlToBlocks 的 case 'pre' 分支 - splitOversizedBlock 添加 pre 不拆分规则 - isPureImagePage 跳过 data-converted=true 的图片避免误判
This commit is contained in:
@@ -116,7 +116,11 @@ var PhoneImageEngine = (function () {
|
||||
// 先渲染内容流(DOM) - 用于实测高度
|
||||
renderContentFlow(blocks);
|
||||
|
||||
// DOM实测高度 - 等待一帧确保渲染完成
|
||||
// 等待一帧确保中间栏渲染完成
|
||||
requestAnimationFrame(function () {
|
||||
// 在中间栏中将表格和代码块截图转为图片
|
||||
convertFlowBlocksToImages(blocks).then(function () {
|
||||
// 再等一帧让替换后的img渲染
|
||||
requestAnimationFrame(function () {
|
||||
measureBlockHeights(blocks);
|
||||
|
||||
@@ -149,6 +153,8 @@ var PhoneImageEngine = (function () {
|
||||
deferred.reject(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
@@ -273,6 +279,12 @@ var PhoneImageEngine = (function () {
|
||||
block.estimatedHeight = 0;
|
||||
block.needsMeasurement = true;
|
||||
break;
|
||||
case 'pre':
|
||||
block.type = 'pre';
|
||||
block.html = $el[0].outerHTML;
|
||||
block.estimatedHeight = 0;
|
||||
block.needsMeasurement = true;
|
||||
break;
|
||||
case 'img':
|
||||
// 尝试从data属性计算比例高度, 否则标记需要DOM测量
|
||||
var imgW = parseInt($el.attr('data-original-width'), 10);
|
||||
@@ -483,6 +495,11 @@ var PhoneImageEngine = (function () {
|
||||
return [block];
|
||||
}
|
||||
|
||||
// 代码块不拆分,保留原样
|
||||
if (block.type === 'pre') {
|
||||
return [block];
|
||||
}
|
||||
|
||||
// 文本类块:按句子拆分
|
||||
var text = '';
|
||||
var wrapperTag = 'p';
|
||||
@@ -666,112 +683,6 @@ var PhoneImageEngine = (function () {
|
||||
return { type: 'summary', html: html };
|
||||
}
|
||||
|
||||
// ===== 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);
|
||||
});
|
||||
|
||||
// 逐个截图替换,每次重新查找避免 replaceWith 后索引失效
|
||||
function convertNext() {
|
||||
var $pre = $staging.find('pre').first();
|
||||
if ($pre.length === 0) {
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
convertNext();
|
||||
}).catch(function () {
|
||||
// 截图失败则跳过当前元素继续处理下一个
|
||||
$pre.remove();
|
||||
convertNext();
|
||||
});
|
||||
}
|
||||
|
||||
convertNext();
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 #render-staging 中的表格转为图片
|
||||
* 使用 html2canvas 截图替换(与 convertCodeBlocks 模式相同)
|
||||
* @returns {jQuery Deferred} resolves when all tables are converted
|
||||
*/
|
||||
function convertTables() {
|
||||
var deferred = $.Deferred();
|
||||
var $staging = $('#render-staging');
|
||||
|
||||
// 逐个截图替换,每次重新查找避免 replaceWith 后索引失效
|
||||
function convertNext() {
|
||||
var $table = $staging.find('.page-content table').first();
|
||||
if ($table.length === 0) {
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
html2canvas($table[0], {
|
||||
scale: 2,
|
||||
useCORS: true,
|
||||
backgroundColor: '#ffffff',
|
||||
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'
|
||||
});
|
||||
$table.replaceWith($img);
|
||||
convertNext();
|
||||
}).catch(function () {
|
||||
// 截图失败则跳过当前元素继续处理下一个
|
||||
$table.remove();
|
||||
convertNext();
|
||||
});
|
||||
}
|
||||
|
||||
convertNext();
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
// ===== 纯图片页优化 =====
|
||||
|
||||
/**
|
||||
@@ -794,6 +705,9 @@ var PhoneImageEngine = (function () {
|
||||
var $imgs = $content.find('img');
|
||||
if ($imgs.length !== 1) return false;
|
||||
|
||||
// 跳过由表格/代码块转换而来的图片(不应被当作纯图片页处理)
|
||||
if ($imgs.first().attr('data-converted') === 'true') return false;
|
||||
|
||||
// img必须有有效src
|
||||
var src = $imgs.first().attr('src');
|
||||
return src && src.length > 0;
|
||||
@@ -876,17 +790,8 @@ var PhoneImageEngine = (function () {
|
||||
requestAnimationFrame(function () {
|
||||
// html2canvas会跳过visibility:hidden的元素,临时切换为可见
|
||||
$staging.css({ visibility: 'visible' });
|
||||
// 先转换代码块为图片
|
||||
convertCodeBlocks().then(function () {
|
||||
return convertTables();
|
||||
}).then(function () {
|
||||
// 表格和代码块已在中间栏中转为图片,无需再次转换
|
||||
runCaptureLoop($staging, opts, deferred);
|
||||
}).catch(function () {
|
||||
// 代码块转换失败,继续转换表格并截图流程
|
||||
convertTables().then(function () {
|
||||
runCaptureLoop($staging, opts, deferred);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1062,6 +967,68 @@ var PhoneImageEngine = (function () {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 在中间栏 #content-flow 中将表格和代码块截图转为图片
|
||||
* 在 renderContentFlow(blocks) 之后、measureBlockHeights(blocks) 之前调用
|
||||
* @param {Array} blocks - parseHtmlToBlocks 返回的块数组
|
||||
* @returns {jQuery Deferred} resolves with blocks array
|
||||
*/
|
||||
function convertFlowBlocksToImages(blocks) {
|
||||
var deferred = $.Deferred();
|
||||
var $flow = $('#content-flow');
|
||||
|
||||
function convertNextBlock(blockIdx) {
|
||||
// 找到下一个需要转换的 block
|
||||
while (blockIdx < blocks.length) {
|
||||
if (blocks[blockIdx].type === 'table' || blocks[blockIdx].type === 'pre') break;
|
||||
blockIdx++;
|
||||
}
|
||||
if (blockIdx >= blocks.length) {
|
||||
deferred.resolve(blocks);
|
||||
return;
|
||||
}
|
||||
|
||||
var block = blocks[blockIdx];
|
||||
// 在 content-flow 中找到对应的 .content-flow-block
|
||||
var $blockEl = $flow.find('.content-flow-block[data-index="' + blockIdx + '"]');
|
||||
if (!$blockEl.length) {
|
||||
convertNextBlock(blockIdx + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// 对代码块:先应用 Prism 高亮
|
||||
if (block.type === 'pre' && typeof Prism !== 'undefined') {
|
||||
$blockEl.find('pre > code:not([class*="language-"])').addClass('language-plaintext');
|
||||
$blockEl.find('pre code').each(function () { Prism.highlightElement(this); });
|
||||
}
|
||||
|
||||
// html2canvas 截图
|
||||
var targetEl = $blockEl[0];
|
||||
html2canvas(targetEl, {
|
||||
scale: 2,
|
||||
useCORS: true,
|
||||
backgroundColor: block.type === 'table' ? '#ffffff' : '#f5f5f5',
|
||||
logging: false
|
||||
}).then(function (canvas) {
|
||||
var imgData = canvas.toDataURL('image/jpeg', 0.92);
|
||||
// 替换 block 的 html 和 type
|
||||
block.html = '<img src="' + imgData + '" data-converted="true" style="max-width:100%;height:auto;display:block;margin:10px 0;" />';
|
||||
block.type = 'img';
|
||||
|
||||
// 更新中间栏中的显示
|
||||
$blockEl.html(block.html);
|
||||
|
||||
convertNextBlock(blockIdx + 1);
|
||||
}).catch(function () {
|
||||
// 截图失败,保留原样
|
||||
convertNextBlock(blockIdx + 1);
|
||||
});
|
||||
}
|
||||
|
||||
convertNextBlock(0);
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* DOM实测高度 - 从#content-flow中读取每个块的实际渲染高度
|
||||
* @param {Array} blocks - parseHtmlToBlocks 返回的块数组
|
||||
|
||||
Reference in New Issue
Block a user