学习前提

先完成HTML表单基础;理解name、value及submit事件。

本课完成后你能做什么

跟踪一次提交如何从控件变成数据,并分清原生验证、业务规则与网络请求。

先理解机制

FormData从有name的成功控件收集数据。disabled控件不提交,未勾选复选框也不提交;readonly文本控件通常仍参与提交。id主要用于关联label和脚本定位,不能代替name。多个同名控件可能产生多个值,读取时应使用getAll而不是只取第一个。

required、min、max、type等表达浏览器可理解的约束。checkValidity返回结果,reportValidity还会尝试显示提示。自定义规则用setCustomValidity设置非空错误文字,修正输入后必须设回空字符串,否则控件仍被视为无效。

requestSubmit走类似用户提交的验证与submit事件路径,submit方法则绕过这些环节。脚本需要触发正常提交时优先requestSubmit。监听submit后preventDefault只是取消默认行为,之后仍需要明确写出本地展示或fetch请求。

渐进增强的表单先有可理解的字段和反馈,再增强即时验证。不要在页面载入时给尚未交互的所有输入显示错误。前端规则不能承担服务端权限、唯一性与完整业务校验。

可运行示例

运行方式:将HTML示例保存为独立的.html文件并在浏览器打开;含脚本的示例使用现代浏览器。资源文件与多文件模块另按正文要求准备。

<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Honeysuck practice</title></head><body>
<form id="signup"><label>Name <input name="name" id="name" required maxlength="30"></label>
<fieldset><legend>Topics</legend><label><input type="checkbox" name="topic" value="HTML">HTML</label><label><input type="checkbox" name="topic" value="CSS">CSS</label></fieldset>
<button>Preview data</button></form><pre id="result" role="status"></pre>
<script>
const form=document.querySelector('#signup'),nameInput=document.querySelector('#name');
function validate(){nameInput.setCustomValidity(nameInput.value.trim()?'':'Enter a name, not only spaces.');}
nameInput.addEventListener('input',validate);
form.addEventListener('submit',event=>{event.preventDefault();validate();if(!form.reportValidity())return;
 const data=new FormData(form);document.querySelector('#result').textContent=JSON.stringify({name:String(data.get('name')).trim(),topics:data.getAll('topic')},null,2);
});
</script>
</body></html>

推演与验证

填入名字并选两项,输出topics应包含两个值。取消全部勾选应得到空数组。把name输入临时设为disabled,观察FormData不包含该字段;恢复后再测试纯空格与正常修正。本例只预览数据,不向服务器提交。

常见错误与边界

用户提交之前自定义错误需随着input清除,否则submit事件可能根本触发不到。JSON.stringify不能直接正确序列化FormData为业务对象,需显式读取字段。文件字段也不能当普通字符串处理。

动手练习

要求至少选择一项主题,并将错误关联到主题区域;保留用户已填内容。增加脚本按钮调用requestSubmit,验证与鼠标提交结果一致。

参考解法与理由

可以在第一项复选框上设置组错误,并在所有主题change时重算是否有选中项。给组提示固定id并用aria-describedby关联。不要把每个checkbox都设required,那会变成全部必须选。

进一步阅读