DOM 树与选择器
DOM 把 HTML 解析成节点树。querySelector / querySelectorAll 用 CSS 选择器查找;getElementById 最快但只按 id。
const el = document.querySelector('#app .title');
const items = document.querySelectorAll('li');
items.forEach(li => console.log(li.textContent));频繁访问的节点先存为变量,别在每次事件里反复 querySelector,省去重复查找开销。
增删改节点
用 createElement 创建、append/prepend 插入、remove 删除、classList 管理类。操作应批量、最小化重排。
const li = document.createElement('li');
li.textContent = '新项';
li.classList.add('item');
list.append(li);
// 批量用 DocumentFragment 减少重排
const frag = document.createDocumentFragment();事件模型
事件流分三阶段:捕获(外层向内)、目标、冒泡(内层向外)。addEventListener 默认在冒泡阶段触发,stopPropagation 可阻止继续。
el.addEventListener('click', handler);
el.addEventListener('click', captureHandler, true); // 捕获阶段
// e.stopPropagation() 阻止冒泡;e.preventDefault() 阻止默认行为它会阻断冒泡,可能影响其他合法监听器。仅在确有需要时(如模态内点击不关闭)使用。
事件委托
把子元素的事件监听挂到父容器,利用冒泡统一处理。新增/删除子节点无需单独绑定,性能好、易维护。
list.addEventListener('click', (e) => {
const li = e.target.closest('li'); // 找到实际命中的 li
if (!li) return;
console.log('点了', li.dataset.id);
});BOM 与存储
window/location/history 提供浏览器能力;localStorage(持久)/ sessionStorage(会话)做简单客户端存储。
localStorage.setItem('token', t);
const t = localStorage.getItem('token');
history.pushState({}, '', '/detail/1'); // 不刷新改 URLlocalStorage 可被 XSS 读取,绝不能存 token/密码。鉴权信息用 HttpOnly Cookie 更安全。
表单处理
用 form 的 submit 事件统一处理,FormData 收集字段,配合原生校验属性(required/pattern)提升体验。
form.addEventListener('submit', (e) => {
e.preventDefault();
const data = new FormData(form);
console.log(data.get('email'));
});拖拽与文件
HTML5 拖拽用 drag/drop 事件;文件上传通过 <input type="file"> 或拖放,用 FileReader/URL.createObjectURL 读取。
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
const file = e.dataTransfer.files[0];
const url = URL.createObjectURL(file); // 预览
});常见陷阱与 FAQ
最常见是脚本在 DOM 解析前执行。把脚本放 body 末尾、用 defer,或在 DOMContentLoaded 后绑定。
拼接用户输入到 innerHTML 会造成 XSS。优先用 textContent;必须插入 HTML 时对内容做转义或使用可信模板。
多次读写布局属性会触发强制同步布局。批量修改、用 DocumentFragment、或用 requestAnimationFrame 合并。