在进行高级开发前,必须先掌握 DOM 的底层运行机制,这是实现复杂交互和性能优化的基础。
| 操作类型 | 具体示例 | 优化建议 |
| 修改布局属性 | elem.style.width = '200px'、elem.style.margin = '10px' | 用transform/opacity替代(不触发回流) |
| 改变 DOM 节点结构 | appendChild、removeChild、innerHTML(大量内容) | 用DocumentFragment批量操作,减少操作次数 |
| 获取布局属性(强制同步) | elem.offsetWidth、elem.getBoundingClientRect() | 集中获取,避免在修改布局后立即获取 |
| 调整浏览器窗口大小 | 窗口 resize 事件 | 防抖处理,减少触发频率 |
<!DOCTYPE html><html><head> <meta charset="UTF-8">
<"itit3.ahren.cc">
<"itit3.bayu.cc">
<"itit3.nnlzt.com">
<"itit3.zjjxjl.cn">
<"itit3.dpzz.cn">
<"itit4.ahren.cc">
<"itit4.bayu.cc">
<"itit4.nnlzt.com">
<"itit4.zjjxjl.cn">
<"itit4.dpzz.cn"> <title>回流优化:transform替代传统布局</title> <style> .box { width: 100px; height: 100px; background: #3b82f6; transition: all 0.3s; /* 平滑过渡 */ } /* 传统方式:修改margin,触发回流 */ .box.traditional-move { margin-left: 200px; } /* 优化方式:用transform,仅触发重绘(部分浏览器甚至不触发重绘) */ .box.transform-move { transform: translateX(200px); } </style></head><body> <div id="traditionalBox"></div> <div id="transformBox" style="margin-top: 20px;"></div> <button id="moveBtn" style="margin-top: 20px;">移动盒子</button> <script> const traditionalBox = document.getElementById('traditionalBox'); const transformBox = document.getElementById('transformBox'); const moveBtn = document.getElementById('moveBtn'); let isMoved = false; moveBtn.addEventListener('click', function() { if (isMoved) { traditionalBox.classList.remove('traditional-move'); transformBox.classList.remove('transform-move'); } else { traditionalBox.classList.add('traditional-move'); transformBox.classList.add('transform-move'); } isMoved = !isMoved; }); </script></body></html>
中 级阶段已掌握createElement/appendChild,高级阶段需拓展节点操作能力,应对复杂 DOM 结构处理场景。
<!-- 克隆示例:批量创建表格行 --><table border="1" id="dataTable" style="border-collapse: collapse; margin-top: 20px;"> <thead> <tr> <th>姓名</th> <th>年龄</th> </tr> </thead> <tbody> <tr id="templateRow"> <td></td> <td></td> </tr> </tbody></table><script> const tableBody = document.querySelector('#dataTable tbody'); const templateRow = document.getElementById('templateRow'); // 模拟数据 const userData = [ { name: '张三', age: 25 }, { name: '李四', age: 30 }, { name: '王五', age: 28 } ]; // 克隆模板行并填充数据 userData.forEach(user => { // 深克隆模板行(包含子节点td) const newRow = templateRow.cloneNode(true); // 移除模板行的id(避免id重复) newRow.removeAttribute('id'); // 填充数据 newRow.querySelector('.name').textContent = user.name; newRow.querySelector('.age').textContent = user.age; // 添加到表格 tableBody.appendChild(newRow); }); // 移除原始模板行(仅用于克隆,不显示) templateRow.remove();</script>
中 级阶段已用它批量添加节点,高级阶段可结合 “模板克隆” 实现更复杂的 DOM 生成逻辑,且支持跨文档碎片操作(如合并多个碎片)。
原生 DOM 事件(如click/input)仅能满足基础交互,高级开发中需自定义事件,实现 “组件间通信”“复杂状态同步” 等需求。
| API | 作用 | 语法示例 |
| CustomEvent() | 创建自定义事件对象 | new CustomEvent('eventName', { detail: 数据 }) |
| dispatchEvent() | 触发自定义事件 | elem.dispatchEvent(customEvent) |
| addEventListener() | 监听自定义事件 | elem.addEventListener('eventName', 回调) |
<!DOCTYPE html><html><head> <meta charset="UTF-8">
<"itit1.ahren.cc">
<"itit1.bayu.cc">
<"itit1.nnlzt.com">
<"itit1.zjjxjl.cn">
<"itit1.dpzz.cn">
<"itit2.ahren.cc">
<"itit2.bayu.cc">
<"itit2.nnlzt.com">
<"itit2.zjjxjl.cn">
<"itit2.dpzz.cn"> <title>自定义事件:弹窗组件通信</title> <style> .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); display: none; justify-content: center; align-items: center; } .modal.show { display: flex; } .modal-content { width: 300px; padding: 20px; background: white; border-radius: 8px; } .modal-footer { margin-top: 20px; display: flex; justify-content: flex-end; gap: 10px; } .btn { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; } .btn-primary { background: #3b82f6; color: white; } .btn-secondary { background: #9ca3af; color: white; } </style></head><body> <button class="btn btn-primary" id="openModalBtn">打开弹窗</button> <!-- 弹窗组件 --> <div id="modal"> <div> <h3>自定义事件示例</h3> <p>点击按钮触发自定义事件,实现组件通信</p> <div> <button class="btn btn-secondary" id="cancelBtn">取消</button> <button class="btn btn-primary" id="confirmBtn">确认</button> </div> </div> </div> <script> // 1. 获取元素 const openModalBtn = document.getElementById('openModalBtn'); const modal = document.getElementById('modal'); const cancelBtn = document.getElementById('cancelBtn'); const confirmBtn = document.getElementById('confirmBtn'); // 2. 打开弹窗 openModalBtn.addEventListener('click', function() { modal.classList.add('show'); }); // 3. 弹窗内部:触发自定义事件 function triggerModalEvent(eventName) { // 创建自定义事件,携带弹窗结果数据 const modalEvent = new CustomEvent('modalClose', { bubbles: true, // 允许事件冒泡,方便父元素监听 detail: { result: eventName === 'confirm' ? 'confirmed' : 'cancelled' } }); // 触发事件(从弹窗内容区触发,便于冒泡) modal.querySelector('.modal-content').dispatchEvent(modalEvent); // 关闭弹窗 modal.classList.remove('show'); } cancelBtn.addEventListener('click', () => triggerModalEvent('cancel')); confirmBtn.addEventListener('click', () => triggerModalEvent('confirm')); // 4. 父元素监听自定义事件(实现组件通信) modal.addEventListener('modalClose', function(e) { // 获取自定义事件携带的数据 const result = e.detail.result; // 根据结果执行逻辑(如提交表单、提示用户) if (result === 'confirmed') { alert('用户点击了确认,执行提交逻辑'); } else { alert('用户点击了取消,取消操作'); } }); </script></body></html>
中 级阶段需手动监听用户操作(如click)来感知 DOM 变化,高级阶段可通过MutationObserver自动监听 DOM 节点的 “属性、子节点、文本内容” 变化,实现 “自动同步状态”“动态内容监控” 等需求。
<!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>MutationObserver:监听DOM变化</title> <style> .todo-list { list-style: none; padding: 0; margin: 20px 0; } .todo-item { padding: 8px; margin-bottom: 8px; background: #f3f4f6; border-radius: 4px; } .count-info { font-size: 16px; font-weight: 500; } .btn { padding: 8px 16px; background: #3b82f6; color: white; border: none; border-radius: 4px; cursor: pointer; } </style></head><body> <div>待办项数量:<span id="todoCount">0</span></div> <button id="addTodoBtn">添加待办项</button> <ul id="todoList"></ul> <script> // 1. 获取元素 const todoList = document.getElementById('todoList'); const todoCount = document.getElementById('todoCount'); const addTodoBtn = document.getElementById('addTodoBtn'); let todoId = 1; // 2. 添加待办项(模拟DOM变化) addTodoBtn.addEventListener('click', function() { const todoItem = document.createElement('li'); todoItem.className = 'todo-item'; todoItem.textContent = `待办项 ${todoId}`; todoList.appendChild(todoItem); todoId++; }); // 3. 创建MutationObserver实例,监听todoList变化 const observer = new MutationObserver(function(mutations) { // mutations:变化记录数组,包含所有DOM变化 mutations.forEach(function(mutation) { // 监听子节点变化(添加/删除) if (mutation.type === 'childList') { // 更新待办项计数(直接获取子节点数量) todoCount.textContent = todoList.children.length; } }); }); // 4. 配置监听选项:监听子节点变化 const observerConfig = { childList: true, // 监听子节点添加/删除 subtree: false, // 不监听子节点的子节点(仅监听todoList直接子节点) attributes: false, // 不监听属性变化 characterData: false // 不监听文本内容变化 }; // 5. 启动监听:观察todoList节点 observer.observe(todoList, observerConfig); // 6. (可选)停止监听(如页面销毁时) // observer.disconnect(); </script></body></html>
需求:实现一个 “拖拽排序” 功能 —— 列表项可拖拽调整位置,核心是利用 DOM 的Drag and DropAPI,结合MutationObserver优化排序后的状态同步。
<!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>高级实战:拖拽排序</title> <style> .drag-list { list-style: none; padding: 0; max-width: 400px; margin: 30px auto; } .drag-item { padding: 12px 16px; margin-bottom: 8px; background: #ffffff; border: 1px solid #e5e7eb; border-radius: 6px; cursor: move; transition: all 0.2s; } .drag-item:hover { box-shadow: 0 2px 4px rgba(0,</doubaocanvas>
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70048291/viewspace-3099871/ ,如需转载,请注明出处,否则将追究法律责任。