From 2a3d16fca25ad498a9499e288c973557667ab9bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=B2=E6=82=A6?= Date: Thu, 6 Nov 2025 12:12:08 +0800 Subject: [PATCH] =?UTF-8?q?html=E6=B5=81=E5=BC=8F=E5=93=8D=E5=BA=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/core/app-shell.js | 58 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/js/core/app-shell.js b/js/core/app-shell.js index 17add05..c7fcc08 100644 --- a/js/core/app-shell.js +++ b/js/core/app-shell.js @@ -2083,7 +2083,7 @@ renderHtmlPreview(htmlContent, manifest, options = {}) { if (!this.el.viewer) return; const { partial = false } = options; - const preparedHtml = this.prepareHtmlDocument(htmlContent); + const preparedHtml = this.prepareHtmlDocument(htmlContent, { partial }); this.el.viewer.innerHTML = ''; const wrapper = document.createElement('div'); @@ -2115,16 +2115,66 @@ this.el.viewer.appendChild(wrapper); } - prepareHtmlDocument(htmlContent) { + prepareHtmlDocument(htmlContent, options = {}) { + const { partial = false } = options; const raw = typeof htmlContent === 'string' ? htmlContent.trim() : ''; if (!raw) { return '空白页面
暂无可展示内容
'; } const hasDocumentTag = /]/i.test(raw); if (hasDocumentTag) { - return raw; + return this.ensureHtmlClosingTags(raw, { partial }); } - return `Generated Page${raw}`; + const bodyContent = raw; + const skeleton = `Generated Page${bodyContent}`; + return this.ensureHtmlClosingTags(skeleton, { partial: false }); + } + + ensureHtmlClosingTags(html, options = {}) { + const { partial = false } = options; + let output = html; + + const ensureClosingTag = (tag, insertionStrategy) => { + const openRegex = new RegExp(`<${tag}[\\s>]`, 'i'); + const closeRegex = new RegExp(``, 'i'); + if (!openRegex.test(output) || closeRegex.test(output)) { + return; + } + const closingMarkup = ``; + const insertAt = insertionStrategy(); + if (insertAt < 0 || insertAt > output.length) { + output += `\n${closingMarkup}`; + } else { + output = + output.slice(0, insertAt) + + `\n${closingMarkup}\n` + + output.slice(insertAt); + } + }; + + ensureClosingTag('head', () => { + const bodyIndex = output.search(/]/i); + if (bodyIndex !== -1) return bodyIndex; + const htmlCloseIndex = output.search(/<\/html>/i); + if (htmlCloseIndex !== -1) return htmlCloseIndex; + return output.length; + }); + + ensureClosingTag('body', () => { + const htmlCloseIndex = output.search(/<\/html>/i); + return htmlCloseIndex !== -1 ? htmlCloseIndex : output.length; + }); + + ensureClosingTag('html', () => output.length); + + if (partial) { + // 对流式场景追加最外层闭合,避免 iframe 在标签未闭合时渲染失败 + if (!/