事件传播与默认行为
一次点击会经历捕获、目标和冒泡阶段。事件委托利用冒泡让父节点处理动态子节点,但 stopPropagation() 只应在确实要截断边界时使用。
html
<form id="search"><input name="q"><button>搜索</button></form>
<script>
const search = document.querySelector('#search')
search.addEventListener('submit', event => {
event.preventDefault();
const data = new FormData(event.currentTarget);
console.log(data.get('q'));
});
</script>preventDefault() 取消浏览器默认提交;它不会阻止事件继续冒泡,也不会取消已经发出的网络请求。框架事件处理器同样要先分清这三个责任。
练习
让一个动态添加的列表只注册一个父级点击监听,并只对按钮元素响应;点击链接时保留默认导航。
核心机制与实现
浏览器平台由解析、事件循环、渲染、存储、权限和可观测 API 组成。把任务拆成宏任务、微任务、样式计算和绘制,才能解释顺序。
围绕“事件传播与默认行为”先写出输入 → 中间状态 → 可观察结果,再实现最小闭环。不要把事件监听、异步请求、DOM 读取或 store 写入混在一个函数里;每个副作用都要有创建、完成、取消和清理路径。
js
console.log('script')
queueMicrotask(() => console.log('microtask'))
requestAnimationFrame(() => console.log('paint callback'))
setTimeout(() => console.log('task'), 0)逐步运行:先只验证成功路径,再改变一个输入;记录时间顺序、对象身份、错误类型和最终可见状态。若环境不支持某个浏览器 API,要把静态协议验证和真实浏览器验证分开记录。
失败边界与变体
- 输入为空、重复、过期或非法时,不应静默覆盖有效状态。
- 组件卸载、路由离开、标签页关闭或请求取消时,资源必须停止写入。
- 跨文档、Shadow DOM、Worker、SSR 或多标签页会改变可见边界,不能沿用单页面直觉。
- 需要持久化时记录 schema 版本和迁移失败策略;需要全局状态时先证明局部状态不足。
可运行实验与练习
在真实浏览器记录输出顺序、布局读取和长任务;改变 DOM、网络和定时器,解释哪些工作阻塞输入与绘制。
练习要求:实现一个最小版本,补一个失败测试,再给出一个替代方案及其适用条件。答案应包括实际输入序列、观察结果、修复原因和未覆盖的浏览器差异。