马黑黑 发表于 2026-6-7 09:16

浅谈待预览HTML代码的包装

<style>
    .artBox { margin: 20px auto; font: normal 18px/26px sans-serif; }
    .artBox p { margin: 10px 0; }
</style>

<div class="artBox">
    <p>在线预览 html 代码的效果有很多实现方式,其中,使用“Blob + URL”方法足够轻量、高效。核心代码如下:</p>
    <div class="hEdiv"><pre class="hEpre">
// content 为 html 代码字符串
let content = '&lt;h1&gt;Hello World!&lt;/h1&gt;';
const codeBlob = new Blob(, { type: 'text/html' });
const tmpUrl = window.URL.createObjectURL(codeBlob);
window.open(tmpUrl, '_blank');
    </pre></div>
    <p>Blob(Binary Large Object)对象将文本内容存储为二进制数据对象,window.URL 接口借助 createObjectURL() 静态方法将实例化的 Blob 对象创建为 URL 字符串,“无中生有”地创建了一个可访问的、包含了网页内容的地址,window.open() 方法将其打开,'_blank' 规范了新窗口(标签)的打开方式。</p>
    <p>上述代码示例中的第一行注释提到 html 代码的内容。这些内容不论从何而来,我们可能都应考虑:是否对内容进行包装。一个新的页面,哪怕是无中生有的,它都应该是完备的Web页,换言之,html 代码应该具备完整的DOM结构,至少拥有 &lt;html&gt;、&lt;head&gt; 和 &lt; body &gt; 等三个核心标签,以防止效果预览异常。当接收到的代码不包含有这三个标签,我们需要创建它们,反之,我们就不需要对其进行额外的封装。那么,如何判断提交的代码字串里是否包含有核心三标签?请看如下函数,它可以检测传参字符串参数是否包含Web页结构性核心标签:</p>
    <div class="hEdiv"><pre class="hEpre">
// 判断html代码是否为完整结构
isCompleteHtmlPage(code) {
    const hasHtmlTag = /&lt;html\b[^&gt;]*&gt;/i.test(code);
    const hasHeadOrBody = /&lt;head\b[^&gt;]*&gt;|&lt;\/head&gt;|&lt;body\b[^&gt;]*&gt;|&lt;\/body&gt;/i.test(code);
    return hasHtmlTag && hasHeadOrBody;
}
</pre></div>
    <p>这里,我们使用正则表达式先判断代码字串是否包含 &lt;html ...&gt; 标签,接着判断是否包含 &lt;head&gt; 和 &lt;body ...&gt; 标签,这三个标签同时存在就返回真。这是粗略判断,简单够用,多数情形下完全可以检测用户提交的 html 代码结构中是否包含了核心三标签。</p>
    <p>然后在预览之前,根据判断结果对接收到的内容或包装或不包装:</p>
    <div class="hEdiv"><pre class="hEpre">
// 预览函数
preView = (code) =&gt; {
    let content; // 待预览的完整内容
    // 如果提交的代码包含核心三标签
    if (isCompleteHtmlPage(code)) {
      content = code; // 就无需包装
    // 否则给原始代码加入必要的标签
    } else {
      content = `&lt;html lang="zh"&gt;\n&lt;head&gt;\n&lt;meta charset="utf-8"&gt;\n&lt;title&gt;预览&lt;/title&gt;\n&lt;/head&gt;\n&lt;body&gt;\n${code}\n&lt;/body&gt;\n&lt;/html&gt;`;
    }
    // 预览
    const codeBlob = new Blob(, { type: 'text/html' });
    const tmpUrl = window.URL.createObjectURL(codeBlob);
    window.open(tmpUrl, '_blank');
}
    </pre></div>
    <p>此为<strong>方案一</strong>:正则判断+手动包装。正则表达式处理复杂的结构可能不够牢靠,如果需要相对健壮的解决方案,可以考虑<strong>方案二</strong>:使用现代浏览器自带的 DOMParser() 接口对字符串进行处理,该接口非常主动,对 html 代码会进行核心三标签补全操作。试看如下函数及其应用示例:</p>
    <div class="hEdiv"><pre class="hEpre">
function parseStr2Doc(code) {
    const parser = new DOMParser();
    let doc = parser.parseFromString(code, 'text/html');
    return doc.documentElement.outerHTML;
}
   
let str = '&lt;h1&gt;Hello World&lt;/h1&gt;';
console.log(parseStr2Doc(str));
// -> &lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h1&gt;Hello World&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;
    </pre></div>
    <p>如上注释提供的控制台打印结果所示,DOMParser() API是智能的,传参代码中如果没有三核心标签它会补上。另外,我们可以进一步做包装,比如给 doc 实例化对象追加 meta 和 title 标签,以保证待预览的页面更完整,这将很容易,因为 doc 实例化对象就是一个真实的 DOM(文档模型)结构,完全可以像操作现实 Web 页对象那样给其 head 或 body 等进行 appendChild 操作——包括判断 head 中是否存在 title 标签和给它追加 title 标签。最后要做的,就是将返回或获取到的完整内容提交给预览模块即可大功告成。</p>
    <p>结语:第一种代码包装方法,正则判断后的包装简单够用,优点是可控性更强,缺点是正则的能力可能不适宜解决复杂结构的代码;第二种方法,即使用 DOMParser 处理 DOM 结构应该更强大,优点是智能判断、补全核心标签代码甚至有纠错能力,缺点是可控门槛较高。两种方法使用何者,可根据应用场景和个人能力进行选择。</p>
</div>

<script type="module">
    import hl from 'https://638183.freep.cn/638183/web/js/hl.js';
    const divs = document.querySelectorAll('.hEdiv');
    const pres = document.querySelectorAll('.hEpre');
    divs.forEach((div,idx) => hl.hl(div, pres));
</script>

杨帆 发表于 2026-6-7 12:37

言简意赅,谢谢马老师通俗讲授待预览HTML代码的两种包装方法{:4_190:}

霜染枫丹 发表于 2026-6-7 15:19

好像现在我还清醒,知道这不是我能关联的{:4_173:}{:4_204:}{:4_190:}

马黑黑 发表于 2026-6-7 18:09

霜染枫丹 发表于 2026-6-7 15:19
好像现在我还清醒,知道这不是我能关联的

这个,即便是初级前端程序员,也未必能完全看懂

马黑黑 发表于 2026-6-7 18:09

杨帆 发表于 2026-6-7 12:37
言简意赅,谢谢马老师通俗讲授待预览HTML代码的两种包装方法

{:4_180:}

红影 发表于 2026-6-7 19:28

html代码必须有三个核心标签么,好像我们平时玩的没有的吧。

马黑黑 发表于 2026-6-7 19:32

红影 发表于 2026-6-7 19:28
html代码必须有三个核心标签么,好像我们平时玩的没有的吧。

你玩的是论坛。论坛里,给你的空间是表格的一个单元格(<td>你的帖子代码</td>)。

霜染枫丹 发表于 2026-6-7 21:55

马黑黑 发表于 2026-6-7 18:09
这个,即便是初级前端程序员,也未必能完全看懂

我儿子说我还是有点自知之明,没去想搞懂{:4_173:}{:4_190:}

马黑黑 发表于 2026-6-7 21:59

霜染枫丹 发表于 2026-6-7 21:55
我儿子说我还是有点自知之明,没去想搞懂

这个可能也搞不懂

霜染枫丹 发表于 2026-6-7 22:09

马黑黑 发表于 2026-6-7 21:59
这个可能也搞不懂

我不高考{:4_173:}从根本理解不了,还是看着您一个个写出来就打锣敲鼓最合适{:4_189:}{:4_190:}

马黑黑 发表于 2026-6-7 23:08

霜染枫丹 发表于 2026-6-7 22:09
我不高考从根本理解不了,还是看着您一个个写出来就打锣敲鼓最合适

{:4_180:}

红影 发表于 2026-6-8 14:06

马黑黑 发表于 2026-6-7 19:32
你玩的是论坛。论坛里,给你的空间是表格的一个单元格(你的帖子代码)。

哦,原来是这样,明白了{:4_173:}

马黑黑 发表于 2026-6-8 20:48

红影 发表于 2026-6-8 14:06
哦,原来是这样,明白了

早应该明白的

红影 发表于 2026-6-12 23:29

马黑黑 发表于 2026-6-8 20:48
早应该明白的

之前真的不明白啊,原来我只是在一个单元格里玩的{:4_173:}

马黑黑 发表于 2026-6-13 08:01

红影 发表于 2026-6-12 23:29
之前真的不明白啊,原来我只是在一个单元格里玩的

就像坐高铁,你的空间就是一个座位

红影 发表于 2026-6-13 12:52

马黑黑 发表于 2026-6-13 08:01
就像坐高铁,你的空间就是一个座位

嗯嗯,这个比喻十分形象{:4_187:}

马黑黑 发表于 2026-6-13 13:43

红影 发表于 2026-6-13 12:52
嗯嗯,这个比喻十分形象

还行

红影 发表于 2026-6-13 22:17

马黑黑 发表于 2026-6-13 13:43
还行

这样的比喻很容易理解{:4_173:}

马黑黑 发表于 2026-6-13 22:57

红影 发表于 2026-6-13 22:17
这样的比喻很容易理解

估计你很少查看过论坛网页的源码

红影 发表于 2026-6-14 22:47

马黑黑 发表于 2026-6-13 22:57
估计你很少查看过论坛网页的源码

根本没看过,没这习惯啊{:4_173:}
页: [1] 2 3 4 5
查看完整版本: 浅谈待预览HTML代码的包装