如何在JavaScript输入框change事件回调中显示等待光标?
我明白你的困扰:当通过回车或Tab键触发输入框的change事件时,等待光标始终无法正常显示,但点击输入框外部触发change或者点击按钮时却能正常工作。这其实是因为回车/Tab触发事件时,浏览器的焦点处理和样式重绘时机有特殊逻辑,导致你的现有代码没能及时生效。
问题根源分析
当你在输入框中按回车或Tab时,浏览器会优先处理输入框的焦点切换逻辑,这个过程可能会延迟样式的更新。即使你设置了body.className = 'waiting'并调用body.focus(),浏览器可能还没完成重绘就进入了setTimeout的计算任务,而且输入框的光标样式可能还被浏览器的默认行为保留着。另外,setTimeout(plot, 100)的延迟时间并不一定能保证浏览器完成重绘,不同浏览器的重绘时机有差异,100ms有时候可能不够,反而导致样式更新被延迟。
解决方案
这里有几个调整点,组合起来就能完美解决问题:
1. 强制输入框失去焦点
在设置等待样式前,先让触发事件的输入框失去焦点,确保浏览器不会保留输入框的光标状态:
event.target.blur();
2. 使用requestAnimationFrame确保重绘完成
requestAnimationFrame会在浏览器下一次重绘完成后执行回调,比setTimeout更可靠,能保证等待样式已经生效再执行计算任务:
requestAnimationFrame(() => { setTimeout(plot, 0); // 再套一层setTimeout让计算进入下一个事件循环,避免阻塞重绘 });
3. 扩展等待样式到html元素
有时候body的样式可能被父元素(比如html)影响,把等待样式同时应用到html和body,确保全局生效:
html.waiting, html.waiting * { cursor: wait !important; } body.waiting, body.waiting * { cursor: wait !important; }
4. 简化焦点处理
其实不需要调用body.focus(),只要让输入框blur(),再配合上面的步骤,就能确保光标样式切换。
修改后的核心代码
更新updateLimits函数
function updateLimits(event) { event.preventDefault(); event.stopPropagation(); // 强制触发事件的输入框失去焦点 if (event.target.tagName === 'INPUT') { event.target.blur(); } // 给html和body都加上等待类 document.documentElement.className = 'waiting'; body.className = 'waiting'; // 先等浏览器重绘,再执行计算任务 requestAnimationFrame(() => { // 用setTimeout把计算放到下一个事件循环,避免阻塞UI setTimeout(plot, 0); }); }
更新plot函数(重置样式)
function plot() { // just take some time var n; for (n = 1; n < 999999; n++) { factor(n, Math.sqrt(n) + 1); } // 重置html和body的类 document.documentElement.className = ''; body.className = ''; }
更新CSS样式
body { touch-action: none; } html.waiting, html.waiting *, body.waiting, body.waiting * { cursor: wait !important; } /* 其他原有CSS保持不变 */
为什么这样有效?
event.target.blur()直接让输入框失去焦点,浏览器不会再显示输入光标;requestAnimationFrame确保浏览器先完成等待样式的重绘,再执行计算;- 同时给
html和body加样式,避免任何层级的样式覆盖问题; - 最后用
setTimeout(plot, 0)把计算任务放到下一个事件循环,确保UI线程有足够时间完成样式更新。
你可以试试这个修改后的版本,无论是回车、Tab还是点击外部触发change事件,等待光标都能正常显示了。
内容的提问来源于stack exchange,提问作者user2183078

