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. 音频信号质量的度量标准--MOS得分的由来

    早期语音质量的评价方式是凭主观的,人们在打通电话之后通过人耳来感知语音质量的好坏.1996年国际ITU组织在ITU-T P.800和P.830建议书开始制订相关的评测标准:MOS(Mean Opini ...

  2. auto推导类型注意

    auto推导类型忽略顶层const,不忽略底层const. 顶层const:指针或引用本身是const不可变,也就是指针指向的内存地址不可变,但指向的内存内容可变. 底层const:指针指向的内存地址 ...

  3. vscode远程登陆免密码

    A,B双方通信,A想向B发送信息,又不想让别人知道,使用非对称加密:若A向B发送信息,A需要知道B的公钥简称B-pub,用B-pub加密信息后 发送给B,B再用自己的私钥B-prv解密出信息. A想验 ...

  4. FFmpeg命令行之 Unknown encoder ‘libx264‘

    在执行下面命令进行摄像头采集时,会报错 Unknown encoder 'libx264' ffmpeg -f dshow -i video="C1E Camera" -vcode ...

  5. 【Leetcode 907 907. 子数组的最小值之和】【单调栈dp】

    import java.util.LinkedList; class Solution { public int sumSubarrayMins(int[] arr) { int n = arr.le ...

  6. 大年学习linux(第三节---用户管理)

    三.用户管理 用户和用户组操作命令 ld Finger Pwck 检查/etc/passwd配置文件内的信息与实际主文件夹是否存在,还可比较/etc/passwd和/etc/shadow的信息是否一致 ...

  7. STM32 HAL 使用串口IDLE中断+DMA实现收发

    STM32 HAL 使用串口IDLE中断+DMA实现收发 cubeMX配置 mx配置如下(省去系统时钟,烧录口,工程属性配置) 注意:这里关闭 Force DMA channels Interrupt ...

  8. SQLI-LABS(Less-9、10)

    Less-9(GET-Blind-Time based-Single Quotes) 打开Less-9页面,可以看到页面中间有一句Please input the ID as parameter wi ...

  9. 【福利】JetBrains 全家桶永久免费使用

    Jetbrains系列的IDE公认是最好的集成开发工具,但是收费且挺贵.我们以PhpStorm为例,新用户第一年需要199$,注意是$,还不是人民币,这个价格一上来肯定筛选掉一大批用户.确实好用,所以 ...

  10. C# 使用AForge调用摄像头

    AForge官网地址:http://www.aforgenet.com/framework/ using System; using System.Collections.Generic; using ...