Home > Article > Web Front-end > How to handle the cursor of React input in numerical formatting (details)
The content of this article is about how to deal with the cursor of React input in numerical formatting (details). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you. .
What I’m going to talk about today is about some abnormal behaviors of the React input cursor and the corresponding solutions in scenarios involving numerical formatting. The story begins with an issue. Some users reported that when using the NumberField component to input, the cursor position would be abnormal on Android, resulting in continuous input failing to achieve the expected results. What does the specific performance look like?
Figure 1 Unexpected input behavior under Android
You can see it in Every time formatting occurs on an Android phone, the cursor that should always be at the end will be in the wrong format, causing problems with continuous input. This problem does not appear on PC Chrome or iOS, so it can be determined to be a compatibility issue. But how did this compatibility issue arise?
Analyze the formatting process. As in the above situation, when entering 18758, because the card number needs to be formatted, the original value will be converted into "1875 8", from the string length From the above point of view, from 5 digits to 6 digits, if the cursor position does not jump to the last digit when the value changes, it will stay at the space. It will look like a wrong digit is entered. When inputting continuously, There will be problems.
Judging from the cursor change behavior of the input box, this does not seem to be an abnormal change, it just jumps to the end without responding to the change in value. But the question that arises is why it jumps to the end on iOS and PC Chrome.
#Figure 2: The same code behaves differently under PC Chrome than Android.
So I searched online and found such an issue in React's github, Cursor jumps to end of controlled input. Here @sophiebits(spicyj), one of the main maintainers of React, gave a more precise answer.
Figure 3 sophiebits’ explanation of cursor behavior when React controlled input value changes
It turns out that it’s because of value The changes are very uncertain, so React cannot use a reliable and universal logic to save the cursor position at a suitable position, so React will move the cursor to the last position when re-rendering in controlled mode. . This at least explains why the cursor jumps to the end in PC Chrome and iOS, but I haven't found a reasonable explanation for why Android doesn't show the same behavior.
So is there any way to make the performance on Android consistent with iOS? After a while of reading and trying, I finally found that if the re-rendering process and the onChange of the input are placed in two ticks before and after, the performance of the input in Android can be consistent with that on other platforms, that is, the cursor will jump when re-rendering. At the end, the code is as follows.
import React from 'React'; class Demo extends React.Component { constructor(props) { super(props); this.state = { value: 'xxx', }; } handleChange(e) { const value = e.target.value; // 通过 setTimeout 异步 // 使 re-render 和 onChange 处于两个 tick 中 setTimeout(() => { this.setState({ value, }); }); } render() { return ( <input> { this.handleChange(e); }} /> ); } }
This finally makes the displayed behavior consistent on Android and iOS, and the performance is more in line with expectations under normal input conditions. However, wait, is this okay? From the conclusions drawn in the previous React issue, we can see that no matter how the modification is made, it will jump to the end of the input. What will happen if it is modified from the middle?
Figure 4: Problems will occur during intermediate editing
As can be seen from the above figure, because React will change the cursor no matter what modifications are made. At the end, if you modify it from the middle, the performance will not meet the user's expectations, and there will be no way to achieve continuous input. This time, the behavior of both ends is consistent, both of which are unexpected. .
But there are advantages to not being normal. There is no need to write some ifelse according to the platform, and it can be processed uniformly. From the above discussion, we can know that React does not save the cursor position because there is no general and reliable algorithm to support this behavior. This is because changes in the input may include adding spaces for formatting, filtering out some characters, or triggering certain conditions and directly changing to other characters, and other unpredictable changes. But when it comes to the single scenario of digital formatting, the logic of saving the cursor position becomes much simpler and clearer.
在用户输入的过程中,只存在两种情况,在结尾中追加和在中间修改。在结尾追加的 case 中,例如 18758^ 时,由于一直是在向后追加的状态,我们只要一直保持光标在最后即可(即默认状态 1875 8^ ),在中间编辑的 case 下,光标并不处于结尾,如 187^5 8,此时如果在 7 后面追加了一个 8,那么理想的图标应该维持在 8 之后(即 1878^ 58),此时就应该保存光标的位置在上次 format 之前的状态。
逻辑清楚了,接下来就是如何实现的问题了。那么如何探测和修改光标位置呢?这就涉及了 input 中选区相关的属性,我们知道我们可以通过一些方式(如鼠标拖拽和长按屏幕等)在 input 中完成对一段话的选区,因此光标的位置其实是由选区的开始点(selectionStart)和结束点(selectionEnd)决定的。那么其实我们就可以通过读取,储存和设置这两个属性来达到我们想要实现的目的,实例代码如下。
class Demo extends React.Component { ... componentDidUpdate(prevProps) { const { value } = prevProps; const { inputSelection } = this; if (inputSelection) { // 在 didUpdate 时根据情况恢复光标的位置 // 如果光标的位置小于值的长度,那么可以判定属于中间编辑的情况 // 此时恢复光标的位置 if (inputSelection.start { this.input = c; }} value={this.state.value} onChange={(e) => { this.handleChange(e); }} /> ); } }
至此,我们终于在追加和中间编辑的情况下都实现了我们想要的效果。这是一个比较小的技术点,但是由于里面涉及了一些 React 内部的处理逻辑及平台差异性问题,排查和解决起来并不是那么容易,希望可以给有类似问题的同学在处理时有所启发。
Android
Mozilla/5.0 (Linux; U; Android 8.1.0; zh-CN; CLT-AL00 Build/HUAWEICLT-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/11.9.4.974 UWS/2.13.1.48 Mobile Safari/537.36
iOS
Mozilla/5.0 (iPhone; CPU iPhone OS 11_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15F79
PC Chrome
Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36
SaltUI: https://github.com/salt-ui/sa...
The above is the detailed content of How to handle the cursor of React input in numerical formatting (details). For more information, please follow other related articles on the PHP Chinese website!