contenteditable 交互式教程 - 百灵AI🧠 contenteditable 深度交互教程
每个示例均可直接编辑,右侧实时显示 HTML 输出。点击按钮体验高级功能!
基础可编辑段落 & 实时输出
原理: 添加 contenteditable="true"
属性使任何元素可编辑。
特点: - 支持富文本(粘贴带格式文本、Ctrl+B 加粗等)
- 输入时自动更新 innerHTML
- 占位符通过 CSS :empty 伪类实现
这是可编辑段落。试试:选中文字后按 Ctrl+B 加粗,或粘贴带格式的文本。
// 编辑内容将实时显示在这里...
工具栏带格式的编辑器
原理: 使用 document.execCommand()
(虽然已废弃但广泛兼容)或现代 Selection API
注意: execCommand 在现代项目中建议用库替代(如 Tiptap),但此例用于教学
// 格式化后的HTML将显示在这里
UX智能占位符 & 输入检测
技术: - CSS :empty:not(:focus):before
实现无 JS 占位符
- JS 监听 input
事件实现动态提示
数据表格单元格编辑
应用场景: 在线 Excel、数据看板、后台管理系统
实现: 为每个 td
添加 contenteditable
,监听变化保存数据
产品 | 价格 | 库存 |
---|
iPhone 15 | ¥7999 | 100 |
MacBook Pro | ¥12999 | 45 |
// 点击保存查看 JSON 数据
高级多用户编辑模拟(带光标显示)
模拟原理: - 通过 input
事件广播变更- 使用不同颜色边框区分用户- 实际项目需配合 WebSocket + Operational Transformation
你的编辑区(蓝色边框)
开始输入,右侧将实时同步显示
安全防止 XSS 攻击的内容清洗
风险: 用户可能粘贴 <script>alert('XSS')</script>
解决方案: 提交前用 textContent
或 DOMPurify 清洗 HTML
尝试粘贴:<script>alert('XSS!')</script>
或 <img src=x onerror=alert(1)>
// 安全输出将显示在这里
<script>// 全局状态指示器控制function setStatus(id, isEditing) {const indicator = document.getElementById(id);indicator.classList.toggle('editing', isEditing);}// 示例1:实时输出HTMLconst demo1 = document.getElementById('demo1');const output1 = document.getElementById('output1');demo1.addEventListener('focus', () => setStatus('status1', true));demo1.addEventListener('blur', () => setStatus('status1', false));demo1.addEventListener('input', () => {output1.textContent = demo1.innerHTML;});// 示例2:富文本工具栏function formatText(command, value = null) {document.execCommand(command, false, value);updateOutput2();}function insertLink() {const url = prompt('请输入链接地址:', 'https://');if (url) document.execCommand('createLink', false, url);updateOutput2();}function clearFormat() {document.execCommand('removeFormat', false, null);updateOutput2();}function updateOutput2() {document.getElementById('output2').textContent = document.getElementById('demo2').innerHTML;}const demo2 = document.getElementById('demo2');demo2.addEventListener('focus', () => setStatus('status2', true));demo2.addEventListener('blur', () => setStatus('status2', false));demo2.addEventListener('input', updateOutput2);// 示例3:占位符与字符统计const demo3 = document.getElementById('demo3-placeholder');const charCount = document.getElementById('charCount');demo3.addEventListener('input', () => {charCount.textContent = `字符数: ${demo3.textContent.length}`;});function togglePlaceholder() {const placeholder = demo3.getAttribute('data-placeholder');if (demo3.textContent.trim() === '') {demo3.innerHTML = `
占位符已禁用 - 现在为空区域`;} else {demo3.innerHTML = ''; // 清空后CSS占位符重新出现}}// 示例4:表格数据提取function saveTableData() {const rows = document.querySelectorAll('#editableTable tr');const data = [];rows.forEach(row => {const cells = row.querySelectorAll('td');data.push({product: cells[0].innerText,price: cells[1].innerText,stock: cells[2].innerText});});document.getElementById('tableOutput').textContent = JSON.stringify(data, null, 2);}// 监听表格编辑状态document.querySelectorAll('#editableTable td').forEach(td => {td.addEventListener('focus', () => setStatus('status4', true));td.addEventListener('blur', () => setStatus('status4', false));});// 示例5:协作编辑模拟const collabEditor = document.getElementById('collab-editor');const collabViewer = document.getElementById('collab-viewer');collabEditor.addEventListener('input', () => {// 模拟网络延迟setTimeout(() => {collabViewer.innerHTML = collabEditor.innerHTML;}, 300 + Math.random() * 500);setStatus('status5', true);setTimeout(() => setStatus('status5', false), 1000);});// 示例6:安全清洗演示function showUnsafeHTML() {const html = document.getElementById('unsafe-editor').innerHTML;document.getElementById('safeOutput').innerHTML = `
危险输出(未清洗):\n${html}`;}function showSafeText() {const text = document.getElementById('unsafe-editor').textContent;document.getElementById('safeOutput').textContent = `安全文本(纯文本):\n${text}`;}function showSafeHTML() {const dirty = document.getElementById('unsafe-editor').innerHTML;// 使用浏览器DOM清洗(简单示例)const div = document.createElement('div');div.textContent = dirty; // 自动转义HTMLconst clean = div.innerHTML;// 更专业的做法:使用 DOMPurify.sanitize(dirty)document.getElementById('safeOutput').innerHTML = `
清洗后HTML(安全):\n${clean}`;}// 实时状态检测document.querySelectorAll('[contenteditable="true"]').forEach(el => {el.addEventListener('focus', () => {document.getElementById('globalStatus').classList.add('editing');});el.addEventListener('blur', () => {document.getElementById('globalStatus').classList.remove('editing');});});// 初始化输出window.onload = () => {output1.textContent = demo1.innerHTML;updateOutput2();};</script>