不能只写 onblur="save()",因为 onblur 高频触发易导致重复提交、覆盖未响应结果、漏存粘贴内容,且移动端软键盘收起时触发不稳定,必须配合防抖、变更检测、状态标记与幂等处理。

直接用 onblur 触发保存逻辑,但必须配合防抖、状态标记和接口幂等处理,否则容易重复提交或丢数据。
为什么不能只写 onblur="save()"
用户频繁点击切换焦点(比如在文本域和按钮间来回点),onblur 会高频触发;后端若没做幂等校验,可能存入多条重复记录;更糟的是,如果保存接口异步未完成,用户又快速编辑再失焦,第二次请求可能覆盖第一次的未响应结果。
- 浏览器原生
onblur不带节流能力,纯靠 JS 手动控制 - 用户复制粘贴大段内容后直接点保存按钮,
onblur可能还没触发,导致最新内容没存 - 移动端软键盘收起时,
onblur触发时机不稳定,有时晚于页面滚动或 tab 切换
textarea 的 onblur + 防抖 + 变更检测怎么写
核心是:只在内容真有变化、且停顿 500ms 后才发请求。不依赖全局定时器,每个 textarea 独立维护自己的 timer 和上一次值。
- 给
textarea加data-last-value属性,初始设为当前值 -
onblur里先比对this.value和this.dataset.lastValue,不等才执行保存 - 用
clearTimeout+setTimeout实现单次防抖,timer 存在this._saveTimer上避免闭包泄漏 - 保存成功后,更新
dataset.lastValue = this.value,并清除 timer
```html <textarea id="content" data-last-value="" onblur="handleBlur(this)"></textarea> ```
```javascript
function handleBlur(el) {
const cur = el.value.trim();
const last = el.dataset.lastValue || '';
if (cur === last) return;
<p>clearTimeout(el._saveTimer);
el._saveTimer = setTimeout(() => {
fetch('/api/save', {
method: 'POST',
body: JSON.stringify({id: el.id, content: cur})
}).then(res => res.json())
.then(data => {
if (data.code === 0) {
el.dataset.lastValue = cur;
}
});
}, 500);
}</p><pre class='brush:</pre>;toolbar:false;'>
<H3>和 Layui 表单验证共存要注意什么</H3>
<p>Layui 的 <code>form.verify</code> 默认只在提交时校验,但如果你把保存逻辑塞进 <code>form.on('submit')</code>,就和 <code>onblur</code> 冲突了——用户还没编辑完就点了提交按钮,<code>onblur</code> 可能还在 pending 中。</p>
<ul>
<li>不要在 <code>form.on('submit')</code> 里再调一次保存,应确保 <code>onblur</code> 已完成或跳过它</li>
<li>可在提交前加个标记 <code>el.dataset.isSubmitting = '1'</code>,<code>handleBlur</code> 检测到该标记就直接 return</li>
<li>如果用了 <code>lay-verify</code>,注意 <code>onblur</code> 触发时机早于验证,需手动调用 <code>form.validate(id)</code> 确保字段合法再发保存请求</li>
</ul>
<H3>移动端软键盘收起时 <code>onblur</code> 失效怎么办</H3>
<p>iOS Safari 和部分 Android 浏览器中,软键盘收起不一定会触发 <code>blur</code>,尤其当页面有 <code>position: fixed</code> 元素遮挡时。</p>
<ul>
<li>监听 <code>window.addEventListener('resize')</code>,结合 <code>document.activeElement === textarea</code> 判断是否是键盘收起</li>
<li>更稳妥的是加一个「保存草稿」按钮,放在输入框下方固定位置,用 <code>onclick</code> 显式触发保存</li>
<li>不要依赖 <code>focusout</code> 替代 <code>blur</code> —— 它冒泡且兼容性差,Layui 的弹层、下拉框会干扰事件流向</li>
</ul>
<p>真正难的不是写那几行 <code>onblur</code>,而是判断什么时候不该保存——比如用户只是点选文字没修改,或者正在输入标点符号中途停顿。这些边界情况得靠 <code>dataset.lastValue</code> 和防抖时间窗口一起卡住。</p>


















