默认行为、取消与用户手势
先从一个浏览器可观察问题开始:同一操作为什么会改变节点、事件、请求、存储或辅助技术状态?本节把“默认行为、取消与用户手势”拆成输入、所有者、中间状态和输出,避免只背 API。
最小实验
把下面内容保存为 default-action.html 后直接打开。点击链接时页面地址不应改变;提交表单时页面不应刷新,并且控制台应分别打印两条取消日志。
html
<a id="link" href="https://example.com">打开链接</a>
<form id="form"><button type="submit">提交</button></form>
<script>
const link = document.querySelector('#link')
const form = document.querySelector('#form')
link.addEventListener('click', (event) => {
event.preventDefault()
console.log('link default cancelled')
})
form.addEventListener('submit', (event) => {
event.preventDefault()
console.log('form default cancelled')
})
</script>先记录点击前的地址和表单提交次数,再删除其中一个 preventDefault() 比较地址栏与刷新行为;最后把它换成 stopPropagation(),观察事件传播改变但默认行为仍会发生。
规则与边界
- 平台保证、浏览器实现和业务约定必须分开;一个浏览器中的结果不能自动推广到所有宿主。
- 每个监听器、请求、观察器、缓存和焦点操作都要有清理/取消责任;页面或组件离开后不能继续写状态。
- 用户输入、URL、HTML、消息和持久化数据按不同信任边界处理;类型正确不代表内容可信。
- 失败、取消、超时、权限拒绝、配额不足和不支持要有不同的可观察结果。
机制拆解
默认行为是浏览器在事件监听器结束后继续执行的动作,例如链接导航、表单提交和复选框状态改变。preventDefault() 只取消默认行为,不会阻止事件继续传播;stopPropagation() 只改变传播路径,不会取消导航。把两个动作分开验证,才能避免用错误的 API 修复问题。
可运行实验
html
<a id="link" href="https://example.com">打开链接</a>
<form id="form"><button>提交</button></form>
<script>
const link = document.querySelector('#link')
const form = document.querySelector('#form')
link.addEventListener('click', event => { event.preventDefault(); console.log('navigation cancelled') })
form.addEventListener('submit', event => { event.preventDefault(); console.log('submit cancelled') })
</script>先点击链接和提交按钮,再删除 preventDefault() 比较地址栏和页面刷新行为;将监听器改成 stopPropagation(),确认它不能阻止默认导航。
练习
- 在链接监听器中分别使用
preventDefault()、stopPropagation()和两者都不用,记录地址栏、刷新次数与父级监听器日志。 - 把表单按钮改成
type="button",解释为什么提交事件消失,以及这和取消默认行为的责任不同。 - 为键盘 Enter 提交和鼠标点击各写一条可观察断言,说明哪些行为属于浏览器默认动作,哪些来自脚本。
下一步
完成答案核对后继续本章下一篇,并把实验日志保存在自己的项目中。