浏览器端实现类似input限制输入两位小数,输入时光标从输入位置移动到最后
1.问题描述展示
示例代码所做限制为不允许输入字母d,其他限制规则可以根据需求自己调整,使用React编写,其他框架或原生均可根据该代码理解原理进行转变,特意使用了中文键盘可以看到输入框下面白色框闪出,就是我按下了键盘d键
1) gif图示例

2)代码
import { useState } from "react"
export default function () {
const [value, setValue] = useState(1234)
const onChange = (e) => {
const inputValue = e.nativeEvent.target.value
const value = inputValue.replace('d', '')
setValue(value)
}
return <div style={{marginTop:200}}>
<h3>焦点修改实例:不允许输入字母 d 无处理情况</h3>
<input value={value} onChange={onChange}></input>
</div>
}
3)原因分析
假设目前输入值为1234,光标移动到2后面并输入字母d ,此时输入框得到的输入值为12d34,而我们通过代码将本来应该是12d34的值修改为了1234,也就导致了光标定位到了最后一位
之所以这样处理,猜想大概是因为通过代码进行值的修改的时候存在多种情况比如
a. 1234 => 12456 位数增多
b. 1234 => 12 位数变少
c. 1234 => 5678 值全变化
浏览器实现时为了统一这种情况 只要当浏览器输入框获取的输入值与设置的值不等的时候都重置光标位置
react使用value对输入框输入值做控制的流程为: (以输入框已经输入1234 光标移动到2后面输入d为例)
1.按下d键
2.输入框获得值12d34,但是此时输入框的值受value控制,onChange事件中如果不对value做修改则不会改变输入框实际展示值 (也就是说12d34浏览器输入框内部已经获取到的值为12d34,只是页面并未变化,页面变化由input上的value控制)
3.输入框onChang事件触发,此时代码处理,会将输入框获取值由本应该设置为12d34,修改为了1234,光标重置到最后面 (即输入框内部获取的值如果不等于value值就会光标重置到最后面)
2.解决方案
1)宏任务延时处理
原理为通过input.setSelectionRange改变光标位置,具体api细节自行百度参考文档
import { useState } from "react"
export default function () {
const [value1, setValue1] = useState(1234)
const onChange1 = (e) => {
const start = e.target.selectionStart
const inputValue = e.nativeEvent.target.value
const value = inputValue.replace('d', '')
const input = e.nativeEvent.target
setValue1(value)
setTimeout(() => {
inputValue.includes('d') && input.setSelectionRange(start - 1, start - 1)
}, 0)
}
return <div style={{marginTop:200}}>
<h3>焦点修改实例:不允许输入字母 d 宏任务处理</h3>
<input value={value1} onChange={onChange1}></input>
</div>
}

虽然能够让光标位置正确,但是多次输入的时候存在光标从最后面移动到原位置的情况
2) 微任务处理(关于微任务宏任务可以自行百度了解)
import { useState } from "react"
export default function () {
const [value2, setValue2] = useState(1234)
const onChange2 = (e) => {
const start = e.target.selectionStart
const inputValue = e.nativeEvent.target.value
const value = inputValue.replace('d', '')
const input = e.nativeEvent.target
setValue2(value)
new Promise(res => {
res()
// promist.then的回调函数属于微任务
}).then(() => {
inputValue.includes('d') && input.setSelectionRange(start - 1, start - 1)
})
}
return <div style={{marginTop:200}}>
<h3>焦点修改实例:不允许输入字母 d 微任务处理</h3>
<input value={value2} onChange={onChange2}></input>
</div>
}

3.总结
输入框onChange修改value值导致的光标定位到最后的时机在微任务和宏任务的前面,
即 顺序为 1.重置光标 => 2.微任务 =>(浏览器内部重置光标)界面重新渲染 => 3.宏任务
其中使用宏任务二者执行间隔时间跨度大,导致重置光标界面已经发生变化,宏任务执行恢复光标,导致看到光标从最后移动到代码设置的位置(即:浏览器执行恢复光标 =>界面重新渲染 ,光标移动到最后 => 代码设置光标位置 => 浏览器重新渲染,恢复到代码设置的位置)
微任务则缩小了间隔或者说顺序 (即:浏览器执行恢复光标 => 代码设置光标位置 => 浏览器重新渲染,设置为代码设置的位置)
但是该代码仅仅处理了简单的情况即每次只输入一位的情况,还存在一些边界情况未处理,例如直接复制dddd,调整输入位置,粘贴就会导致光标位置后移,此种情况就需要对原值与新输入值做对比并进行处理
浏览器端实现类似input限制输入两位小数,输入时光标从输入位置移动到最后的更多相关文章
- input和React-Native的TextInput的输入限制,只能输入两位小数(阻止0开头的输入),类似价格限制
一.背景: 想要实现一功能: 1. 最多只能输入两位小数,类似的价格限制 2. 实时监听限制输入,禁止输入不符合规范的字符(当输入违禁字符,进行删除操作) 这样做的优点: 1. 在用户输入时直接进行限 ...
- Android限定EditText的输入类型为数字或者英文(包括大小写),EditText,TextView只能输入两位小数
Android限定EditText的输入类型为数字或者英文(包括大小写) // 监听密码输入框的输入内容类型,不可以输入中文 TextWatcher mTextWatcher = new Tex ...
- OC UITextField只允许输入两位小数
//只能输入两位小数 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range r ...
- angularjs控制输入框只输入数字及最多输入两位小数
ps:示例中作用在循环中,其它的你可以按实际需求进行修改使用 <input type="text" ng-model="item.productNumber&quo ...
- 转载:html+js实现只允许输入两位小数的输入框
JS代码: <script language="JavaScript" type="text/javascript"> function clear ...
- 【devexpress】spinEdit控件如何设置只能输入两位小数
只需设置对应的正则表达式即可,我这里设置的是n2意思就是两位小数的意思 效果如下
- ios TextField限制输入两位小数
只需要实现textField的这个代理方法就可以实现 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange: ...
- 【前端开发】限制input输入保留两位小数
<input type="text" name='amount' id="cash_num" placeholder="请输入金额" ...
- 【jQuery、原生】键盘键入两位小数
jquery的处理办法 <!doctype html> <html lang="en"> <head> <meta charset=&qu ...
- codevs 1206 保留两位小数
http://codevs.cn/problem/1206/ 1206 保留两位小数 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 青铜 Bronze 题解 查看运行结果 ...
随机推荐
- STM32 LwIP学习过程问题总结(一):LwIP ping不通,抓包发现ICMP校验和为0x0000
一.问题 今天在将之前的STM32 LwIP1.4.1版本程序移植到2.1.2版本上时,发现ping不同,但是开发板有ICMP回复包,黄颜色警告checksum为0x0000.说明LwIP移植应该是没 ...
- roadmap - json格式的 思维导图
roadmap - json格式的 思维导图 前端路线图 http://www.bitcountrys.com/frontend.html https://gitee.com/ironman1987/ ...
- 别名路径跳转 - vscode 插件
别名路径跳转 - vscode 插件
- GDB简洁指南
启动gdb:gdb program 设置运行参数:set args 10 20 30 启动程序: run(r),start 显示源代码:list(l) 显示当前栈帧和运行行:frame(f) 设置显示 ...
- String.equals(Object anObject)方法
首先注意,equals()方法接受的是Object类型的对象,并不一定是String类型. public boolean equals(Object anObject) { //两个对象地址是否一样, ...
- 【2311. 小于等于 K 的最长二进制子序列】贪心
class Solution { public static void main(String[] args) { Solution solution = new Solution(); System ...
- SqlSugar的几种连接方式
1.最简单的使用 public class DatabaseService { private static readonly Lazy<SqlSugarClient> _db = new ...
- iOS模拟器 Unable to boot the Simulator —— Ficow笔记
本文首发于 Ficow Shen's Blog,原文地址: iOS模拟器 Unable to boot the Simulator -- Ficow笔记. 内容概览 前言 终结模拟器进程 命令行改权限 ...
- 如何使用LOTO示波器 绘制 频率响应特性曲线?
在工作和项目中,经常会遇到一个功能电路模块对信号进行调理,或滤波,或放大,或衰减,或阻抗变换.这些功能电路模块可能是无源阻容的,也可能是有源的运放电路,也可能是更复杂的系统.但是它们对信号进行调理的最 ...
- 【虚幻引擎】DTWebSocketServer 蓝图创建WebSocket服务器插件使用说明
本插件可以使用蓝图创建WebSocket服务器,并监听响应数据. 下载地址在文章最后. 1. 节点说明 Create Web Socket Server – 创建WebSocket服务器对象并开启监听 ...