feat(phoneimage): 三列布局重构 - 添加渲染预览区并改造渲染管线

- 增加中间渲染预览列(540px),三列布局:编辑器 | 预览 | 缩略图
- CSS作用域迁移:排版样式从#editor-text-area迁移到#render-preview
- 编辑器恢复干净默认样式,消除表格/图片间隙和溢出问题
- 新增syncPreview()实时同步编辑器内容到预览区(300ms防抖)
- captureEditorBlocks()改为从预览区DOM测高,不再克隆编辑器DOM
- render()改为从预览区读取已预处理HTML,所见即所得
This commit is contained in:
augushong
2026-05-12 23:12:48 +08:00
parent ccbfdde73e
commit 29dbc7ca55
3 changed files with 144 additions and 97 deletions

View File

@@ -95,9 +95,10 @@ var PhoneImageEngine = (function () {
var pageHeight = sizeConfig.height;
var contentAreaHeight = pageHeight - (config.contentPadding * 2);
// 从 wangeditor 读取内容
var editorHtml = window.phoneImageEditor ? window.phoneImageEditor.getHtml() : postData.content_html;
var cleanHtml = preprocessContent(editorHtml);
// 从预览区读取已预处理的内容
syncPreview();
var previewEl = document.getElementById('render-preview');
var cleanHtml = previewEl ? previewEl.innerHTML : '';
var blocks = parseHtmlToBlocks(cleanHtml);
// 空内容检测
@@ -111,7 +112,7 @@ var PhoneImageEngine = (function () {
pages.push(generateCoverPage(sizeConfig));
// 内容分页(使用 captureEditorBlocksT3 会完善截图逻辑)
captureEditorBlocks(editorHtml, blocks, contentAreaHeight, sizeConfig).then(function(contentPages) {
captureEditorBlocks(cleanHtml, blocks, contentAreaHeight, sizeConfig).then(function(contentPages) {
pages = pages.concat(contentPages);
// 尾页
@@ -194,6 +195,15 @@ var PhoneImageEngine = (function () {
return html;
}
/**
* 同步渲染预览区 - 将编辑器HTML写入预览区
*/
function syncPreview() {
var html = window.phoneImageEditor ? window.phoneImageEditor.getHtml() : postData.content_html;
var cleanHtml = preprocessContent(html);
$('#render-preview').html(cleanHtml);
}
/**
* 将HTML解析为块级元素数组
* 每个块: { type, html, estimatedHeight }
@@ -354,7 +364,6 @@ var PhoneImageEngine = (function () {
if (blocks[i].type === 'page-break') {
if (currentGroup.blocks.length > 0) groups.push(currentGroup);
currentGroup = { blocks: [], domIndices: [] };
// page-break 对应 wangeditor 中的 divider(hr),在 DOM 中也是一个子元素
domIdx++;
continue;
}
@@ -369,70 +378,55 @@ var PhoneImageEngine = (function () {
return deferred.promise();
}
// 获取编辑器子元素
var editorChildren = getEditorChildren();
// 创建测量容器500px = 540 - 20*2 padding与内容区一致
var $mc = $('<div>').css({
width: '500px',
position: 'fixed',
left: '-9999px',
top: '0',
visibility: 'hidden',
background: '#ffffff',
fontSize: '14px',
lineHeight: '1.8',
boxSizing: 'border-box'
});
$('body').append($mc);
// 串行测高每组
var gi = 0;
function measureNext() {
if (gi >= groups.length) {
$mc.remove();
// 给尚未设置高度的 block 设默认值
for (var k = 0; k < blocks.length; k++) {
if (!blocks[k].estimatedHeight) {
blocks[k].estimatedHeight = 40;
}
}
// 用测量的实际高度后的 blocks 调用原有 paginateContent 分页
var contentPages = paginateContent(blocks, contentAreaHeight, sizeConfig);
deferred.resolve(contentPages);
return;
// 从 #render-preview 获取子元素(已预处理的干净内容)
var previewEl = document.getElementById('render-preview');
if (!previewEl) {
// fallback: 如果预览区不存在给所有block设默认高度
for (var k = 0; k < blocks.length; k++) {
if (!blocks[k].estimatedHeight) blocks[k].estimatedHeight = 40;
}
var contentPages = paginateContent(blocks, contentAreaHeight, sizeConfig);
deferred.resolve(contentPages);
return deferred.promise();
}
var previewChildren = Array.prototype.slice.call(previewEl.children);
// 逐组测高
for (var gi = 0; gi < groups.length; gi++) {
var group = groups[gi];
$mc.empty();
var groupHeight = 0;
for (var j = 0; j < group.domIndices.length; j++) {
var di = group.domIndices[j];
if (di < editorChildren.length) {
$mc.append(editorChildren[di].cloneNode(true));
if (di < previewChildren.length) {
var rect = previewChildren[di].getBoundingClientRect();
groupHeight += Math.round(rect.height);
}
}
requestAnimationFrame(function () {
var h = Math.round($mc[0].getBoundingClientRect().height);
if (groupHeight === 0) groupHeight = group.blocks.length * 40;
// 按比例分配测量的实际高度给组内各个 block
var totalEstimated = 0;
for (var k = 0; k < group.blocks.length; k++) {
totalEstimated += (group.blocks[k].estimatedHeight || 40);
}
for (var k = 0; k < group.blocks.length; k++) {
var ratio = (group.blocks[k].estimatedHeight || 40) / (totalEstimated || 1);
group.blocks[k].estimatedHeight = Math.round(h * ratio);
}
gi++;
measureNext();
});
// 按比例分配测量的实际高度给组内各个 block
var totalEstimated = 0;
for (var k = 0; k < group.blocks.length; k++) {
totalEstimated += (group.blocks[k].estimatedHeight || 40);
}
for (var k = 0; k < group.blocks.length; k++) {
var ratio = (group.blocks[k].estimatedHeight || 40) / (totalEstimated || 1);
group.blocks[k].estimatedHeight = Math.round(groupHeight * ratio);
}
}
measureNext();
// 给尚未设置高度的 block 设默认值
for (var k = 0; k < blocks.length; k++) {
if (!blocks[k].estimatedHeight) {
blocks[k].estimatedHeight = 40;
}
}
var contentPages = paginateContent(blocks, contentAreaHeight, sizeConfig);
deferred.resolve(contentPages);
return deferred.promise();
}
@@ -1348,6 +1342,7 @@ var PhoneImageEngine = (function () {
generateImages: generateImages,
saveImages: saveImages,
saveConfig: saveConfig,
syncPreview: syncPreview,
setPageAlignment: setPageAlignment,
exportLongImage: exportLongImage,
getContentHtml: function () {