复选框已经执行取消操作,页面却仍然显示为选中,这时要分别检查 input 的真实状态和组件绘制的外观。

2018 年的一次项目排查中,attr、prop 都尝试过,最后通过开发者工具对比发现:父节点的样式类控制着选中效果。当前 checked property 与那层 CSS 没有同步。

先读当前 property,不只看 HTML 属性

对于 jQuery 1.6 及以上:

var checkbox = $("#cb1");
if (checkbox.length) {
    var checkedNow = checkbox.prop("checked");
    var matchesChecked = checkbox.is(":checked");
    checkbox.prop("checked", false);
}

checked attribute 主要表达初始状态,运行时的 checked property 表达当前状态。开发者工具里属性文字没变,不足以判断操作是否失败。jQuery prop

设置时使用布尔值 true/false,不用字符串 “checked” 代替当前布尔状态;读取前先确认选中的是实际 input,而不是外层装饰元素。

再核对组件外观

当时的处理片段如下,类名仅对应那个组件:

var inputs = $(".checkbox__button");
inputs.prop("checked", false);
inputs.parent().removeClass("checkbox--checked checkbox__button--focus");

它说明当时需要同步两层状态,不意味着所有组件都应该删这两个类。若组件提供公开的值更新 API,应优先使用该 API;直接删类可能绕过内部模型和可访问性状态。

尤其不要把焦点样式一律当作选中样式删除。键盘用户仍需要明确的焦点位置,焦点与 checked 本来就是两件事。

程序赋值和事件通知也分开

prop 修改当前值,不等于自动执行业务 change 处理器。如果现有组件约定必须通过事件同步,可在确认不会造成递归、重复请求后使用:

$("#cb1").prop("checked", false).trigger("change");

这不是每个场景都必须追加的操作。事件是否需要、由谁触发,应与组件和业务监听保持一致。

最后用鼠标、键盘和程序赋值分别核对当前 property、页面外观和表单数据。未勾选的普通 checkbox 通常不会作为成功控件提交其值;不要只看“灯灭了”就判断数据已正确传到服务器。