????????我們繼續來看一下如何開發一個簡單的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標簽的話就非常簡單了