轻量、安全、易用的HTML测试运行预览工具(修改)
修改后的版本更加灵活!可视化控制台面板会捕获 console.log、info、warn 的输出,并实时显示。内置帮助。
该工具不依赖任何后端服务——不需要联网,所有代码解析、渲染、帮助文档均内嵌在HTML文件中。您可以下载该文件,在离线环境下直接用浏览器打开,所有功能正常工作。
唯一的例外是:如果您的代码中引用了外部网络资源(如图片、CDN脚本),预览时自然需要网络加载这些资源,但工具本身与网络无关。
介绍
轻量、安全、易用的HTML代码测试运行工具,核心价值在于:
· 零依赖(纯 HTML/CSS/JS 实现,无需后端);
· 沙箱隔离保障运行安全;
· 开箱即用的示例代码,降低使用门槛。
· 这是一个纯前端工具,所有代码处理、预览和帮助功能都在您的浏览器中本地完成。
使用方法
左右分栏:左侧代码编辑器,右侧沙箱预览。在编辑器中输入代码。点击“运行”按钮或 Ctrl+Enter 立即预览渲染结果——渲染出网页的样子。
几点说明:
智能代码识别:自动区分纯JS、纯CSS、HTML片段或完整页面,无需手动添加<script>或<style>标签,直接输入代码即可预览。
代码编辑与实时预览:页面采用左右分栏布局。左侧是代码编辑器,您可以直接编写HTML、CSS或JavaScript代码。右侧是预览面板,点击“运行代码”按钮后,代码会在一个沙箱隔离的iframe中渲染,确保运行环境安全,不会影响主页面。
状态反馈与快捷操作:顶部工具栏会清晰显示运行状态(如“就绪”、“渲染中”)。您可以使用Ctrl+Enter快捷键快速运行代码。工具栏上还提供了“重置示例” 按钮,方便您随时恢复内置的卡片示例代码。可视化控制台面板会捕获 console.log、info、warn 的输出,并实时显示。
清除功能:代码编辑器标题栏和工具栏都新增了“清除代码” 按钮。点击后,会清空左侧编辑器,并将右侧预览区替换为一个友好的空白引导页,提示您开始编写新代码。
运行截图及源码
运行截图:

源码(修改)如下:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>HTML运行器 - 安全沙箱预览</title>
<style>
* { box-sizing: border-box; }
body {
background: #1e1f2c;
font-family: 'Segoe UI', 'Fira Code', monospace;
margin: 0; padding: 20px; height: 100vh;
display: flex; flex-direction: column;
}
.toolbar {
background: #2d2f3e; border-radius: 16px; padding: 12px 20px;
margin-bottom: 20px; display: flex; gap: 16px; align-items: center;
flex-wrap: wrap; box-shadow: 0 4px 12px rgba(0,0,0,0.3);
}
.toolbar button {
background: #4c6ef5; border: none; color: white; font-weight: bold;
padding: 8px 24px; border-radius: 40px; font-size: 1rem;
cursor: pointer; transition: 0.2s; font-family: inherit;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
}
.toolbar button:hover { background: #5f7bf6; transform: scale(1.02); }
.toolbar button:active { transform: scale(0.98); }
.toolbar button.clear-btn { background: #e03e3e; }
.toolbar button.clear-btn:hover { background: #f04a4a; }
.toolbar button.help-btn { background: #8b5cf6; }
.toolbar button.help-btn:hover { background: #a78bfa; }
.toolbar span {
color: #ccc; background: #1e1f2c; padding: 4px 12px;
border-radius: 30px; font-size: 0.85rem;
}
.split-container {
display: flex; flex: 1; gap: 20px; min-height: 0;
}
.editor-pane, .preview-pane {
flex: 1; display: flex; flex-direction: column; border-radius: 20px;
overflow: hidden; box-shadow: 0 8px 20px rgba(0,0,0,0.3);
}
.editor-pane { background: #282a36; }
.editor-header, .preview-header {
padding: 12px 16px; font-weight: 600;
border-bottom: 1px solid #44475a;
}
.editor-header { background: #21222c; color: #bd93f9; }
.preview-header { background: #f1f3f5; color: #2c3e66; display: flex; justify-content: space-between; align-items: center; }
textarea {
flex: 1; background: #282a36; color: #f8f8f2; border: none;
padding: 20px; font-family: 'Fira Code', monospace; font-size: 14px;
line-height: 1.5; resize: none; outline: none; tab-size: 4;
}
iframe { width: 100%; flex: 1; border: none; background: white; }
.status-msg { font-size: 12px; background: #e9ecef; padding: 4px 12px; border-radius: 20px; color: #495057; }
.modal-overlay {
display: none;
position: fixed; top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.7); z-index: 1000;
justify-content: center; align-items: center;
}
.modal-overlay.active { display: flex; }
.modal-content {
background: #2d2f3e; color: #e2e8f0; border-radius: 24px;
max-width: 600px; width: 90%; max-height: 80vh; overflow-y: auto;
padding: 32px; box-shadow: 0 20px 40px rgba(0,0,0,0.5);
position: relative;
}
.modal-content h2 { color: #bd93f9; margin-top: 0; }
.modal-content h3 { color: #f1c40f; margin-top: 24px; }
.modal-content ul { padding-left: 20px; }
.modal-content li { margin: 8px 0; line-height: 1.5; }
.modal-content code {
background: #1e1f2c; padding: 2px 6px; border-radius: 4px;
font-family: 'Fira Code', monospace; color: #f8f8f2;
}
.modal-content .close-btn {
position: absolute; top: 16px; right: 20px;
background: none; border: none; color: #aaa; font-size: 28px;
cursor: pointer; line-height: 1;
}
.modal-content .close-btn:hover { color: white; }
.modal-content kbd {
background: #44475a; padding: 2px 8px; border-radius: 6px;
font-family: 'Fira Code', monospace; font-size: 0.9rem;
border: 1px solid #6272a4;
}
@media (max-width: 700px) {
.split-container { flex-direction: column; }
body { padding: 12px; }
.modal-content { padding: 24px; }
}
</style>
</head>
<body>
<div class="toolbar">
<button id="runBtn">▶ 运行代码</button>
<button id="resetBtn">↺ 重置示例</button>
<button id="clearBtn" class="clear-btn">🗑 清除代码</button>
<button id="helpBtn" class="help-btn">❓ 帮助</button>
<span>⚡ 安全沙箱 | 支持 HTML/CSS/JS</span>
<span id="runtimeStatus" class="status-msg">就绪</span>
</div>
<div class="split-container">
<div class="editor-pane">
<div class="editor-header">📝 代码编辑器 (可编辑)</div>
<textarea id="codeArea" spellcheck="false" placeholder="在这里编写 HTML/CSS/JS 代码..."></textarea>
</div>
<div class="preview-pane">
<div class="preview-header">
<span>🖥️ 实时预览 (沙箱隔离)</span>
<span style="font-size:12px;">🔒 iframe sandbox</span>
</div>
<iframe id="previewFrame" sandbox="allow-same-origin allow-scripts allow-popups allow-forms allow-modals" title="代码预览"></iframe>
</div>
</div>
<div id="helpModal" class="modal-overlay">
<div class="modal-content">
<button class="close-btn" id="closeHelpBtn">×</button>
<h2>📘 使用帮助</h2>
<p>欢迎使用HTML运行器!本工具提供一个<strong>安全的沙箱环境</strong>,让您即时预览HTML、CSS和JavaScript代码。</p>
<h3>✨ 智能代码识别</h3>
<ul>
<li><strong>纯JS代码:</strong>直接输入 <code>alert('你好')</code> 或 <code>console.log('测试')</code> 等,会自动包裹 <code><script></code> 标签。console.log('测试')等控制台输出在预览区底部显示。</li>
<li><strong>纯CSS代码:</strong>输入 <code>body { background: red; }</code> 会自动用 <code><style></code> 包裹并应用样式。</li>
<li><strong>HTML片段:</strong>输入 <code><h1>标题</h1></code> 或混合内容,会自动补全文档结构,并附带控制台面板。</li>
<li><strong>完整HTML页面:</strong>如果代码以 <code><!DOCTYPE html></code> 或 <code><html></code> 开头,将保持原样渲染(不添加额外控制台面板)。</li>
</ul>
<h3>⚡ 快捷键</h3>
<ul>
<li><kbd>Ctrl</kbd> + <kbd>Enter</kbd> (Windows/Linux) 或 <kbd>Cmd</kbd> + <kbd>Enter</kbd> (Mac):快速运行代码。</li>
</ul>
<h3>🛠️ 功能按钮</h3>
<ul>
<li><strong>▶ 运行代码:</strong>将编辑器中的代码渲染到右侧预览区。</li>
<li><strong>↺ 重置示例:</strong>恢复内置的欢迎页面示例。</li>
<li><strong>🗑 清除代码:</strong>清空编辑器并显示空白提示页。</li>
<li><strong>❓ 帮助:</strong>显示本帮助窗口。</li>
</ul>
<h3>🔒 安全说明</h3>
<p>所有代码均在 <code>sandbox</code> 属性的iframe中运行,允许脚本、弹窗、表单等,但与主页面隔离,不会影响工具本身。</p>
</div>
</div>
<script>
const codeArea = document.getElementById('codeArea');
const runBtn = document.getElementById('runBtn');
const resetBtn = document.getElementById('resetBtn');
const clearBtn = document.getElementById('clearBtn');
const helpBtn = document.getElementById('helpBtn');
const closeHelpBtn = document.getElementById('closeHelpBtn');
const helpModal = document.getElementById('helpModal');
const previewFrame = document.getElementById('previewFrame');
const runtimeStatus = document.getElementById('runtimeStatus');
// 改进的控制台面板:浅色背景、清晰可见、确保执行顺序
const CONSOLE_INJECT = `
<div id="__console_panel" style="position:fixed;bottom:0;left:0;right:0;background:rgba(255,255,255,0.95);color:#1e293b;font-family:'Fira Code',monospace;font-size:13px;max-height:35%;overflow-y:auto;padding:10px 14px;z-index:99999;border-top:2px solid #cbd5e1;box-shadow:0 -4px 12px rgba(0,0,0,0.1);min-height:36px;">
<div id="__console_placeholder" style="color:#94a3b8;">📋 控制台输出将显示在此处</div>
</div>
<script>
(function() {
var panel = document.getElementById('__console_panel');
var placeholder = document.getElementById('__console_placeholder');
if (!panel) return;
function addLog(level, args) {
// 首次添加日志时移除占位提示
if (placeholder) {
placeholder.remove();
placeholder = null;
}
var msg = args.map(function(a) {
if (typeof a === 'object') {
try { return JSON.stringify(a, null, 2); } catch(e) { return String(a); }
}
return String(a);
}).join(' ');
var entry = document.createElement('div');
entry.style.margin = '3px 0';
entry.style.padding = '2px 0';
entry.style.borderBottom = '1px solid #e2e8f0';
switch(level) {
case 'error': entry.style.color = '#dc2626'; break;
case 'warn': entry.style.color = '#d97706'; break;
case 'info': entry.style.color = '#2563eb'; break;
default: entry.style.color = '#1e293b';
}
entry.textContent = '[' + level.toUpperCase() + '] ' + msg;
panel.appendChild(entry);
panel.scrollTop = panel.scrollHeight;
}
var orig = {};
['log','info','warn','error','debug'].forEach(function(m) {
orig[m] = console[m];
console[m] = function() {
addLog(m, Array.prototype.slice.call(arguments));
orig[m].apply(console, arguments);
};
});
window.addEventListener('error', function(e) {
addLog('error', [e.message]);
});
})();
<\/script>`;
const DEFAULT_CODE = `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>动态预览</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: linear-gradient(145deg, #f5f7fc 0%, #e9eef5 100%);
display: flex; justify-content: center; align-items: center;
min-height: 100vh; font-family: 'Segoe UI', Roboto, system-ui, sans-serif;
padding: 20px;
}
.card {
background: rgba(255,255,255,0.9); backdrop-filter: blur(10px);
border-radius: 48px; padding: 32px 40px;
box-shadow: 0 25px 45px rgba(0,0,0,0.15), 0 2px 5px rgba(0,0,0,0.05);
text-align: center; max-width: 500px; transition: transform 0.2s;
border: 1px solid rgba(255,255,255,0.5);
}
.card:hover { transform: scale(1.01); }
h1 { color: #1e293b; margin-bottom: 16px; font-size: 2.2rem; }
p { color: #334155; margin: 12px 0; line-height: 1.5; }
button {
background: #3b82f6; border: none; color: white; padding: 10px 28px;
border-radius: 40px; font-size: 1rem; cursor: pointer; margin-top: 20px;
transition: background 0.2s; font-weight: 500;
}
button:hover { background: #2563eb; }
.highlight { background: #fef9c3; color: #854d0e; padding: 4px 12px; border-radius: 40px; display: inline-block; }
footer { margin-top: 20px; font-size: 0.75rem; color: #64748b; }
</style>
</head>
<body>
<div class="card">
<h1>✨ HTML运行器 ✨</h1>
<p>恭喜!<span class="highlight">默认预览功能正常</span></p>
<p>您可以编辑左侧代码,点击 <strong>▶ 运行代码</strong> 实时查看效果。</p>
<button id="demoBtn">点我试试 (交互)</button>
<footer>完全沙箱隔离 | 支持 JS/CSS/HTML</footer>
</div>
<script>
document.getElementById('demoBtn')?.addEventListener('click', () => {
alert('🎉 交互成功!您可以在编辑区写任何HTML/CSS/JS代码');
});
<\/script>
</body>
</html>`;
function isLikelyCSS(code) {
if (/\b(function|var|let|const|document|console|alert|=>|new |this\.|\.innerHTML|\.body)\b/.test(code)) return false;
if (/[.#]?[a-zA-Z]+\s*\{[^}]*:[^}]*\}/.test(code)) return true;
return false;
}
function runCode() {
let code = codeArea.value;
if (!code.trim()) {
runtimeStatus.textContent = '⚠️ 代码为空,加载示例…';
code = DEFAULT_CODE;
codeArea.value = DEFAULT_CODE;
}
runtimeStatus.textContent = '⏳ 渲染中…';
const trimmedCode = code.trim();
const hasCompleteHTML = /<!DOCTYPE\s+html/i.test(trimmedCode) || /<html[\s>]/i.test(trimmedCode);
const hasScriptTag = /<script[\s>]/i.test(trimmedCode);
const startsWithHTML = /^\s*<[a-zA-Z!]/.test(code);
try {
if (!hasCompleteHTML && !hasScriptTag && !startsWithHTML) {
if (isLikelyCSS(code)) {
// CSS 自动包裹
code = `<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>CSS 预览</title><style>${code}</style></head>
<body><div style="padding:2rem;color:#666;">✨ CSS 样式已应用(查看背景/布局变化)</div>${CONSOLE_INJECT}</body></html>`;
runtimeStatus.textContent = '🎨 检测到 CSS 代码,已用 <style> 包裹';
} else {
// JS 自动包裹:控制台注入在前,用户代码用 setTimeout 延迟执行确保劫持先生效
code = `<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>JS 预览</title></head>
<body>${CONSOLE_INJECT}
<script>
setTimeout(function() {
${code}
}, 0);
<\/script></body></html>`;
runtimeStatus.textContent = '🔍 检测到纯JS代码,已自动包裹 <script>(控制台面板已启用)';
}
} else if (!hasCompleteHTML) {
// HTML 片段:尝试将控制台注入放在最前面,但不能保证捕获所有同步脚本
if (!/meta\s+charset/i.test(code)) {
code = `<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>预览</title></head><body>${CONSOLE_INJECT}${code}</body></html>`;
} else {
code = `<!DOCTYPE html><html lang="zh-CN"><head><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>预览</title></head><body>${CONSOLE_INJECT}${code}</body></html>`;
}
runtimeStatus.textContent = '📄 HTML片段已补全文档结构(控制台面板已启用)';
}
// 完整HTML不做任何注入,保持原样
const blob = new Blob([code], { type: 'text/html' });
const url = URL.createObjectURL(blob);
previewFrame.onload = () => {
URL.revokeObjectURL(url);
runtimeStatus.textContent = '✅ 预览已更新 (沙箱隔离)';
};
previewFrame.src = url;
} catch (err) {
console.error(err);
runtimeStatus.textContent = '❌ 代码解析失败: ' + err.message;
previewFrame.srcdoc = `<html><body style="background:#fff1f0;font-family:sans-serif;padding:2rem;"><h3>代码错误</h3><pre>${err.message}</pre></body></html>`;
}
}
function resetExample() {
codeArea.value = DEFAULT_CODE;
runtimeStatus.textContent = '🔄 已重置示例,正在渲染…';
runCode();
}
function clearCode() {
codeArea.value = '';
runtimeStatus.textContent = '🗑 代码已清除,预览区已清空';
const emptyPageHTML = `<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>空白预览</title>
<style>*{margin:0;padding:0;box-sizing:border-box;}body{background:#f8f9fa;display:flex;justify-content:center;align-items:center;min-height:100vh;font-family:'Segoe UI',sans-serif;color:#6c757d;}.empty-state{text-align:center;padding:40px;}.empty-state .icon{font-size:4rem;margin-bottom:20px;}.empty-state h2{font-size:1.5rem;margin-bottom:10px;color:#495057;}.empty-state p{font-size:0.95rem;line-height:1.6;}.empty-state .hint{margin-top:16px;padding:10px 20px;background:#e9ecef;border-radius:30px;font-size:0.85rem;display:inline-block;}</style></head>
<body><div class="empty-state"><div class="icon">📝</div><h2>代码编辑区已清空</h2><p>请在左侧编辑器中编写 HTML/CSS/JS 代码,<br>然后点击 <strong>▶ 运行代码</strong> 查看效果。</p><span class="hint">💡 提示:点击 ↺ 重置示例 可恢复默认代码</span></div></body></html>`;
try {
const blob = new Blob([emptyPageHTML], { type: 'text/html' });
const url = URL.createObjectURL(blob);
previewFrame.onload = () => URL.revokeObjectURL(url);
previewFrame.src = url;
} catch (err) {
previewFrame.srcdoc = emptyPageHTML;
}
codeArea.focus();
}
helpBtn.addEventListener('click', () => {
helpModal.classList.add('active');
});
closeHelpBtn.addEventListener('click', () => {
helpModal.classList.remove('active');
});
helpModal.addEventListener('click', (e) => {
if (e.target === helpModal) helpModal.classList.remove('active');
});
codeArea.value = DEFAULT_CODE;
runBtn.addEventListener('click', runCode);
resetBtn.addEventListener('click', resetExample);
clearBtn.addEventListener('click', clearCode);
window.addEventListener('load', () => runCode());
codeArea.addEventListener('keydown', (e) => {
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
e.preventDefault();
runCode();
}
});
</script>
</body>
</html>
你可以试一试。
测试用例
以下是测试代码,您可以直接复制到编辑器中运行,验证
①直接输入JS代码或使用<script>包裹JS代码皆可
如:
alert('交互成功!您可以在编辑区写任何HTML/CSS/JS代码');
或
<script>
alert('交互成功!您可以在编辑区写任何HTML/CSS/JS代码');
</script>
都可以。
②测试用例列表
|
编号 |
输入代码(粘贴到编辑器) |
预期效果 |
测试重点 |
|
1 |
alert('你好,沙箱!') |
弹出提示框 |
纯JS自动包裹:无需手动写<script>,系统应自动补全文档并执行 |
|
2 |
document.body.innerHTML = '<h1>动态生成</h1>'; |
页面显示大标题“动态生成” |
纯JS操作DOM:验证JS对body的修改是否生效 |
|
3 |
console.log('测试消息'); console.info('这是一条 info 消息'); console.warn('这是一条 warn 警告'); |
控制台无输在预览区底部显示。 |
无界面JS:代码执行 |
|
4 |
body { background: tomato; } |
页面背景变为番茄色 |
纯CSS自动补全:纯CSS代码会自动补全为完整HTML并应用样式 |
|
5 |
<h1>Hello World</h1> |
页面显示一级标题 |
HTML片段补全:自动添加<html>,<head>,<body>结构 |
|
6 |
<style>p { color: blue; }</style><p>蓝色文字</p> |
蓝色段落文字 |
混合片段:同时包含style和普通标签,无需DOCTYPE也能正确渲染 |
|
7 |
空内容(清空编辑器后运行) |
自动加载默认示例卡片 |
空输入处理:应显示带渐变背景的默认欢迎页 |
|
8 |
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>完整页</title> </head> <body> <h1>完整页面</h1> </body> </html> |
显示“完整页面”标题 |
完整文档保持原样:不做任何修改直接渲染 |
|
9 |
<img src="https://picsum.photos/200" alt="示例图片"> |
显示一张随机图片 |
外部资源加载:验证图片能否正常请求和显示 |
|
10 |
setTimeout(() => { document.body.innerHTML += '<p>延迟出现</p>'; }, 1000); |
1秒后页面出现“延迟出现”段落 |
异步JS:验证定时器能否在沙箱中正常工作 |
③ 较复杂用例
a.测试多console.log()
let age = 12; // 把数字12放进"age"盒子
let name = "小明"; // 把文字放进"name"盒子
console.log(name,"我今年", age, "岁");
age = age + 1; // age变成13
console.log("明年我就", age, "岁了");
let hero = "哈利";
let score = 100;
console.log(`勇士${hero}获得了${score}分!`);
b. 测试 HTML 结构
<h1>你好,世界!</h1>
<p>这是一个纯 HTML 测试。</p>
c. 测试 CSS 样式
<style>
body { background: #ffeaa7; font-family: sans-serif; }
.box {
width: 200px; height: 200px; background: #fd79a8;
margin: 50px auto; border-radius: 20px;
display: flex; align-items: center; justify-content: center;
color: white; font-size: 24px;
}
</style>
<div class="box">CSS 样式正常</div>
d. 测试 JavaScript 交互
<button οnclick="document.getElementById('msg').textContent = 'JS 运行成功!'">
点击测试 JavaScript
</button>
<p id="msg"></p>
e. 综合计数器(HTML + CSS + JS)
<style>
body { font-family: Arial; text-align: center; padding-top: 80px; }
button { padding: 10px 20px; font-size: 20px; margin: 10px; }
#count { font-size: 48px; color: #2d3436; }
</style>
<h1>简单计数器</h1>
<p id="count">0</p>
<button οnclick="change(-1)">➖ 减少</button>
<button οnclick="change(1)">➕ 增加</button>
<script>
let num = 0;
function change(delta) {
num += delta;
document.getElementById('count').textContent = num;
}
</script>
534

被折叠的 条评论
为什么被折叠?



