跳到主要内容

变更事件与表单提交

change 与 input 的触发时机差在哪?​

事件何时触发特点
change元素的值"改完了"文本输入要等失焦才触发
input值被用户每一次修改立即触发, 不依赖键盘
  • 文本输入: 打字过程中没有 change, 点到别处 (或按 Tab) 时才触发一次;
  • select、input type=checkbox/radio: 选择一变就立刻触发 change;
  • input 覆盖面更广: 鼠标粘贴、语音识别输入都会触发, 因为只看"值变了没";
  • input 不触发的情况: 值没变动的按键, 例如方向键 ← →;
  • 想捕捉每一次修改, 选 input; 想在"输完"时处理, 选 change;
  • input 里不能 preventDefault(): 它在值已改完之后才触发, 阻止已经来不及;
input.oninput = () => (result.textContent = input.value);

cut/copy/paste 能拦下什么?​

  • 三者属于 ClipboardEvent, 携带 event.clipboardData;
  • 可中止: 在处理器里 event.preventDefault() 后, 剪切/复制/粘贴都不会发生;
input.onpaste = (event) => {
console.log(event.clipboardData.getData("text/plain"));
event.preventDefault(); // 本次粘贴作废
};
  • 反直觉点: 在 cut/copy 处理器里调用 clipboardData.getData(...) 拿到的是空串, 因为数据此刻还没进剪贴板;
  • 因此要读被选中文本, 用 document.getSelection();
  • clipboardData 实现 DataTransfer 接口, 所以除了文本还能搬运文件等内容;
  • 异步替代: navigator.clipboard 可在任意上下文使用 (需要时向用户申请权限), Firefox 不支持;

剪贴板有哪些安全限制?​

  • 剪贴板是 OS 级全局资源, 页面不能随便读;
  • 浏览器只在用户动作 (复制/粘贴等) 的处理程序内部放开访问;
  • dispatchEvent 合成的剪贴板事件在多数浏览器被禁止, 即便发出也不给剪贴板数据;
  • 把 event.clipboardData 存起来稍后再用同样无效, 它只在用户事件处理器的作用期内可用;

submit 事件何时触发, 怎么用它做校验?​

  • 两条提交途径:
途径说明
点击 <input type="submit"> / type="image"常规提交按钮
在输入框里按 Enter无需点任何按钮
  • 两者都会在 <form> 上触发 submit, 处理程序里校验数据, 有错就 event.preventDefault() (onsubmit 中写 return false), 表单不再发往服务器;
  • 一个有趣细节: 在输入框按 Enter 提交时, <input type="submit"> 上会触发 click 事件, 尽管用户并没有点击;
<form onsubmit="alert('submit!'); return false">
<input type="text" value="text" />
<input type="submit" value="Submit" />
</form>

form.submit() 和触发 submit 事件有什么区别?​

  • form.submit(): 用 JS 直接提交;
  • 关键区别: 不会产生 submit 事件, 也不执行校验 — 默认提交按钮走的是完整流程, 方法是"跳过流程, 直接发";
  • 设计前提: 既然程序员主动调用, 就假定脚本已经做完相关处理;
  • 用途: 动态造一个表单再发给服务器;
const form = document.createElement("form");
form.action = "https://google.com/search";
form.method = "GET";
form.innerHTML = '<input name="q" value="test">';
document.body.append(form); // 必须先入文档, 否则提交无效
form.submit();
  • 需要保留校验与 submit 事件的程序化提交, 用 form.requestSubmit();

HTML 约束校验与 submit 如何分工?​

  • 声明式校验: required、pattern 等输入属性让浏览器先挡一道, 简单场景无需写 JS;
  • 程序化检查与反馈:
方法/属性作用
form.checkValidity()校验并返回布尔值, 不打扰用户
form.reportValidity()校验并在不合规时弹出浏览器自带提示
input.validity逐项读取校验状态 (如 validity.valid)
<form novalidate>关掉浏览器的自动校验, 完全交给自己处理
  • 分工: 浏览器负责拦截与提示, submit 处理程序负责兜底与自定义逻辑;
  • 一致性问题: form.submit() 绕过校验, 所以"校验通过才发送"这类保证必须自己写;