简单实现HTML在线编辑器

发布于:2025-06-18 ⋅ 阅读:(14) ⋅ 点赞:(0)

        我们继续来看一下如何开发一个简单的html在线编辑器,要求很简单 能够同时编辑html,css,js代码,并且运行之后可以同时预览效果


一:前置知识

        在H5中设置了一个新的标签,<iframe>, 用于在当前 HTML 文档中嵌入另一个独立的 HTML 文档。这是实现在线编辑器预览功能的关键,因为它提供了一个沙箱环境,内部的 HTML、CSS、JS 不会直接影响到父页面。所以我们来简单学习一下该标签元素的使用。

(1)核心属性和方法 (用于向 iframe 写入内容):

  iframe 比较特殊,因为它内部有自己独立的 window 对象和 document 对象。你需要先访问到它们:

  • previewFrame.contentWindow: 返回 iframe 的 window 对象。
  • previewFrame.contentDocument: 返回 iframe 的 document 对象。
    • 注意:在某些旧浏览器或特定情况下,contentDocument 可能不可用,更通用的方式是 previewFrame.contentWindow.document

假设我们先获取了一个iframe元素

const previewFriame =document.getElementByID("preview-frame")
方法一 :使用document.write()

这是讲HTML字符串斜土iframe内部文档的传统写法

    const htmlCode = "<h1>Hello from iframe</h1><p>This is a test.</p>";
    const iframeDoc = previewFrame.contentWindow.document;

    iframeDoc.open();     // 1. 打开文档流,准备写入
    iframeDoc.write(htmlCode); // 2. 将 HTML 字符串写入
    iframeDoc.close();    // 3. 关闭文档流,浏览器会解析并显示内容

通过沙箱的contentWindow获取沙箱的内部环境再通过document写入内容

 · open(): 清除 `iframe` 中当前的所有内容,并打开一个新的文档流准备接收数据。

 · write(): 将字符串写入到打开的文档流中。你可以多次调用 `write()` 来追加内容。

 · close(): 关闭文档流。这个步骤很重要,它告诉浏览器所有内容都已写入完毕,可以开始解析和渲染了。如果不调用 `close()`,`iframe` 可能会一直处于加载状态。

方法二:使用`srcdoc` 属性 (更现代,推荐)

`srcdoc` 属性允许你直接将完整的 HTML 内容作为字符串赋值给它。浏览器会将其作为 `iframe` 的源文档内容进行渲染。

  const htmlCode = "<h1>Hello via srcdoc</h1><p>Modern way!</p>";
    previewFrame.srcdoc = htmlCode;

使用这种方法也有一些优点:

 1.更安全:比 `document.write` 在某些情况下更安全,可以减少 XSS 风险(虽然在这个项目中你主要写入自己控制的代码,风险较低)。

2.更简洁:一行代码搞定。

3.行为更像加载一个真正的文档

方法三: 操作 `iframe` 内部 DOM (如果只需要修改部分内容,而不是整个文档)

如果你不是要替换整个 `iframe` 的内容,而是想修改它内部已有的某个元素,可以这样做:

// 假设 iframe 内部已经有一个 id 为 "title" 的 h1 元素
 const iframeDocument = previewFrame.contentWindow.document;
 const titleElementInIframe = iframeDocument.getElementById('title');
 if (titleElementInIframe) {
     titleElementInIframe.textContent = 'New Title in Iframe';
    }

对于在线编辑器,通常我们是替换整个预览内容,所以 `document.write()` 或 `srcdoc` 更常用。

其他属性:

1.src属性 指定iframe要加载的外部页面的url。如果你要加载一个已有的网页,会用这个。对于我们的编辑器 我们是动态生成内容 所以scrdoc或者document.write()

2.`width`, `height`: 设置 `iframe` 的宽高。

3. `sandbox`: (高级) 用于对 `iframe` 内容施加额外的限制,增强安全性。例如,阻止脚本执行、阻止表单提交等。


二 :开发过程

我们总结一下开发任务:

1.  获取 `textarea` 的引用

2.  获取 `iframe` 的引用

3.  给 `textarea` 添加 `input` 事件监听器。

4.  在事件处理函数中:

       获取 `textarea` 的 `.value` (用户输入的 HTML 代码)。

       使用 `iframe.contentWindow.document.open()`, `.write()`, `.close()` **或者** `iframe.srcdoc` 将这段 HTML 代码设置到 `iframe` 中,让它显示出来。

先从这两个元素最核心的用法开始,等把 HTML 预览功能实现了,我们再考虑 CSS 和 JavaScript 的集成,那会涉及到更多 `iframe` 内部的操作。

(1)前端页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Html在线编译器</title>
    <link rel="stylesheet" href="./css/index.css">
    <link rel="stylesheet" href="./css/base.css">
</head>
<body class="body1">
    <div class="left">
        <div class="html">
            <button class="run-html">运行</button>
           <div class="title">html编辑器</div>
           <textarea name="html" id="1" class="htmlInput"></textarea>
        </div>
        <div class="css">
            <div class="title">css编辑器</div>
            <textarea name="css" id="2" class="cssInput"></textarea>
        </div>
        <div class="js">
            <div class="title">js编辑器</div>
            <textarea name="js" id="3" class="jsInput"></textarea>
        </div>
    </div>
    <div class="right">
        <div class="show">
            <div class="title">在线预览</div>
            <!-- iframe标签用于嵌入一个小的html文档窗口 -->
             <!-- iframe里面的内容和外部的相互独立的 互不影响 -->
            <iframe src="about:blank" frameborder="0">1</iframe>
            <!-- frameborder :这个属性用来指定是否显示 <iframe> 的边框。 0 表示没有边框, 1 表示显示边框 -->
        </div>
    </div>
    <script src="./js/index.js"></script>
</body>
</html>

(2)css

*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: Arial, Helvetica, sans-serif;
}
html, body {
    height: 100%;
}

body{
    background-color: #454545;
    display: flex;
}
/* 左 */
.left{
    width: 50vw;
    height: 100%;
    /* background-color: pink; */
    padding: 5vh;
}
.left .html{
    width: 100%;
    height: 30vh;
    border-radius: 5px;
    background-color: #fff;
    margin-bottom: 1vh;
    display: flex;
    flex-direction: column;
    position: relative;
}
.run-html{
    transform: translate(-110%, -110%);
    top: 100%;
    left: 100%;
    position: absolute;
    width: 10vh;
    border-radius: 2vh;
    background-color: #95e330;
}
.run-html:hover{
    background-color: #88d228;
}
.run-html:active{
    background-color: #78c220;
}
.left .css{
    width: 100%;
    height: 30vh;
    border-radius: 5px;
    background-color: #fff;
    margin-bottom: 1vh;
    display: flex;
    flex-direction: column;

}
.left .js{
    width: 100%;
    height: 30vh;
    border-radius: 5px;
    background-color: #fff;
    margin-bottom: 1vh;
    display: flex;
    flex-direction: column;

}
.left .title{
    width: 100%;
    text-align: center;
    border: 0.5px solid #ccc;
}
.left textarea{
    padding: 2px;
    width: 100%;
    height: 100%;
    border: 0;
    box-sizing: border-box;
    flex-grow: 1;
    background-color: #ccc;
}

.left textarea:focus {
    /* 点击输入框不会出现黑边 */
    outline: none;
}
/* 右 */
.right{
    width: 50vw;
    height: 100%;
    /* background-color: skyblue; */
    padding: 5vh;
}

.right .show{
    width: 100%;
    height: 92vh;
    background-color: #fff;
}

.right .title{
    width: 100%;
    text-align: center;
    border: 0.5px solid #ccc;
}

.right iframe{
    width: 100%;
    height: 100%;
}

(3)js

const html=document.querySelector('.htmlInput');
const css=document.querySelector('.cssInput');
const js=document.querySelector('.jsInput');

const btnhtml=document.querySelector('.run-html');
const output=document.querySelector('.show iframe');
function run(){
    output.contentDocument.body.innerHTML = html.value + '<style>' + css.value + '</style>';
    const script = output.contentDocument.createElement('script');
    script.textContent = js.value;
    output.contentDocument.body.appendChild(script);
}
btnhtml.addEventListener('click',run);

就这样吧 实现这个功能如果利用这个iframe标签的话就非常简单了


网站公告

今日签到

点亮在社区的每一天
去签到