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限制输入两位小数,输入时光标从输入位置移动到最后的更多相关文章

  1. input和React-Native的TextInput的输入限制,只能输入两位小数(阻止0开头的输入),类似价格限制

    一.背景: 想要实现一功能: 1. 最多只能输入两位小数,类似的价格限制 2. 实时监听限制输入,禁止输入不符合规范的字符(当输入违禁字符,进行删除操作) 这样做的优点: 1. 在用户输入时直接进行限 ...

  2. Android限定EditText的输入类型为数字或者英文(包括大小写),EditText,TextView只能输入两位小数

    Android限定EditText的输入类型为数字或者英文(包括大小写) // 监听密码输入框的输入内容类型,不可以输入中文    TextWatcher mTextWatcher = new Tex ...

  3. OC UITextField只允许输入两位小数

    //只能输入两位小数 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range r ...

  4. angularjs控制输入框只输入数字及最多输入两位小数

    ps:示例中作用在循环中,其它的你可以按实际需求进行修改使用 <input type="text" ng-model="item.productNumber&quo ...

  5. 转载:html+js实现只允许输入两位小数的输入框

    JS代码: <script language="JavaScript" type="text/javascript"> function clear ...

  6. 【devexpress】spinEdit控件如何设置只能输入两位小数

    只需设置对应的正则表达式即可,我这里设置的是n2意思就是两位小数的意思 效果如下

  7. ios TextField限制输入两位小数

    只需要实现textField的这个代理方法就可以实现 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange: ...

  8. 【前端开发】限制input输入保留两位小数

    <input type="text" name='amount' id="cash_num" placeholder="请输入金额" ...

  9. 【jQuery、原生】键盘键入两位小数

    jquery的处理办法 <!doctype html> <html lang="en"> <head> <meta charset=&qu ...

  10. codevs 1206 保留两位小数

    http://codevs.cn/problem/1206/ 1206 保留两位小数  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 青铜 Bronze 题解  查看运行结果 ...

随机推荐

  1. private priv 私人 pri=prim first v=self 自己第一

    private priv 私人 pri=prim first v=self 自己第一 private v自己-私人的 pri 来自PIE*per,向前,穿过 pri = pre 向前(这么理解也说的过 ...

  2. ADS1299芯片datasheet 重点解析

    一 START和DRDY的关系 start必须要至少提前拉高2个时钟,才会产生DRDY信号,这个非常关键,也是重心所在.很多遗漏的就不会有DRDY信号出来了. 二 START和DRDY的时序图 sta ...

  3. Python 的结构体函数 struct pack, unpack 用法详解

    一 python 结构体 * python struct 模块可以用来在存储二进制文件,广泛用在文件系统,网络连接领域. *  它可以用在c语言和python语言之间的数据的格式转换. 二  Pyth ...

  4. java -jar xxx.jar命令执行jar包时出现Error: Invalid or corrupt jarfile xxx.jar解决方案

    MANIFEST.MF清单文件内容: Manifest-Version: 1.0 Ant-Version: Apache Ant 1.8.2 Created-By: 1.8.0_60-b27 (Ora ...

  5. PAT 甲级【1007 Maximum Subsequence Sum】

    本题是考察动态规划与java的快速输入: max[i]表示第i个结尾的最大的连续子串和.b begin[i]表示第[begin[i],i]为最大和的开始位置 超时代码: import java.io. ...

  6. 程序员必须了解的 10个免费 Devops 工具

    哈喽大家好,我是咸鱼. 近年来,DevOps 已经成为一门将软件开发 (Dev) 与 IT 运维 (Ops) 相融合的重要学科,目的是为了缩短软件的开发生命周期并提供高质量软件的持续交付. 这篇文章整 ...

  7. 使用JMeter从JSON响应的URL参数中提取特定值

    在使用Apache JMeter进行API测试时,我们经常需要从JSON格式的响应中提取特定字段的值.这可以通过使用JMeter内置的JSON提取器和正则表达式提取器来完成.以下是一个具体的例子,展示 ...

  8. SpringBoot集成drools

    目录 1.背景 2.需求 3.实现 3.1 引入jar包 3.2 编写drools配置类 3.3 编写Person对象 3.4 编写drl文件 3.5 编写kmodule.xml文件 3.6 编写Co ...

  9. Java 中文、unicode编码互转 ;汉字、二进制字符串互转

    //中文转unicode编码 public static String gbEncoding(final String gbString) { char[] utfBytes = gbString.t ...

  10. ZYNQ7000系列学习之TF卡读写实验

    TF卡读写实验 1.实验原理 开发板上自动带有TF卡外接接口,这里只需调用封装好的IP核即可实现该功能.当然,你还需要一个TF卡(感觉SD卡也可以,反正这两种卡差不多).实验就是调用一个IP核,不涉及 ...