学习前提
理解函数、数组和HTML属性;准备一个独立练习页面。
本课完成后你能做什么
从用户事件更新状态,再由状态生成界面;避免把界面文本当作数据源。
先理解机制
querySelector 返回首个元素或 null。把脚本放在文档末尾,或使用 defer,确保查询时元素已解析。DOM 是当前页面对象树,不等于最初的 HTML 字符串;修改 DOM 不会自动写回服务器文件。
事件先经过捕获阶段,再到目标,再冒泡。event.target 是起点,currentTarget 是当前监听器绑定的元素。事件委托把监听器放在稳定父容器上,通过 closest 找到操作按钮,再确认按钮属于该容器,适合动态列表。
用户内容使用 textContent 写入,不要拼到 innerHTML。按钮提供键盘语义,表单监听 submit 能覆盖回车提交。preventDefault 阻止默认动作,stopPropagation 阻止传播,两者用途不同,不能互换。
可运行示例
<button id="counter" type="button">Count: 0</button>
<script>
const button = document.querySelector("#counter");
let count = 0;
button.addEventListener("click", () => {
count += 1;
button.textContent = "Count: " + count;
});
</script>
推演与验证
先读代码中计数状态的初始值,再连续点击三次,确认每次只增加一次。用Tab聚焦按钮并按Enter,结果应相同。刷新后状态重新初始化,这不是存储失败,而是本例没有持久化。
常见错误与边界
重复初始化时反复绑定监听器会导致一次点击执行多次。移除监听器需要原来的函数引用;匿名函数重新写一遍不是同一引用。禁用按钮不应作为服务端权限验证。
动手练习
增加减一和重置按钮,约束计数不低于0;把所有DOM更新收敛到一个 render 函数。
参考解法与理由
各处理器只改变状态并调用 render,减一使用 Math.max(0,count-1)。render 同时更新文字与减一按钮的 disabled,防止显示状态分散。