이 글의 내용은 숫자 형식에서 React 입력의 커서를 처리하는 방법(세부 사항)에 대한 내용입니다. 필요한 친구들이 참고하면 좋을 것 같습니다.
오늘 제가 이야기할 내용은 숫자 형식 지정과 관련된 시나리오에서 React 입력 커서의 비정상적인 동작과 이를 처리하는 방법에 대한 것입니다. 이야기는 문제로 시작됩니다. 일부 사용자는 NumberField 구성 요소를 사용하여 입력할 때 Android에서 커서 위치가 비정상적이어서 연속 입력이 예상한 결과를 얻지 못한다고 보고했습니다. 구체적인 성과는 어떤 모습인가요?
그림 1 Android에서 예기치 않은 입력 동작
Android 휴대폰에서 서식이 발생할 때마다 끝에 있어야 할 커서가 잘못 배치되는 것을 볼 수 있습니다. 연속 입력에 문제가 발생합니다. . 이 문제는 PC Chrome이나 iOS에서는 나타나지 않으므로 호환성 문제로 판단할 수 있습니다. 그런데 이 호환성 문제는 어떻게 발생했습니까?
위 상황처럼 18758을 입력하면 카드번호를 포맷해야 하기 때문에 원래 값은 문자열 길이 관점에서 "1875 8"로 변환됩니다. 6자리. 값이 변경될 때 커서 위치가 마지막 자리로 이동하지 않으면 공백에 그대로 유지됩니다. 잘못된 숫자가 입력된 것처럼 나타나 연속 입력 시 문제가 발생합니다.
입력 상자의 커서 변경 동작으로 판단하면 이는 비정상적인 변경은 아닌 것으로 보이며 값 변경에 반응하지 않고 끝으로 점프합니다. 그러나 제기되는 질문은 iOS와 PC Chrome에서 왜 끝까지 점프하는지입니다.
그림 2: 동일한 코드가 Android와 PC Chrome에서 다르게 동작합니다.
그래서 온라인으로 검색한 결과 React의 github에서 커서가 제어된 입력 끝으로 점프하는 문제를 발견했습니다. 여기에 React의 메인 메인테이너 중 한 명인 @sophiebits(spicyj)가 좀 더 정확한 답변을 주었습니다.
그림 3 React 제어 입력 값 변경 시 커서 동작에 대한 sophiebits의 설명
값 변경에는 매우 큰 불확실성이 있기 때문에 React는 신뢰할 수 있고 보편적인 논리를 사용하여 커서 위치를 저장하지 못하는 것으로 나타났습니다. 적절한 위치에 배치되므로 제어 모드에서 React를 다시 렌더링하면 커서가 마지막 위치로 이동됩니다. 이는 적어도 PC Chrome 및 iOS에서 커서가 끝으로 이동하는 이유를 설명하지만 Android에서 동일한 동작을 표시하지 않는 이유에 대한 합리적인 설명을 찾지 못했습니다.
그럼 Android의 성능을 iOS와 일관되게 만들 수 있는 방법이 있나요? 잠시 읽고 시도한 끝에 마침내 리렌더링 프로세스와 입력의 onChange를 두 틱 전후에 배치하면 Android의 입력 성능이 다른 플랫폼의 성능과 일치할 수 있다는 것을 발견했습니다. 즉, 다시 렌더링할 때 커서가 점프하게 됩니다. 마지막으로 코드는 다음과 같습니다.
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); }} /> ); } }
이렇게 하면 마침내 Android와 iOS에서 성능이 일관되게 되고, 일반적인 입력 조건에서는 성능이 기대에 더 부합합니다. 그런데 잠깐, 이거 괜찮을까요? 이전 React 이슈에서 도출된 결론을 보면, 어떻게 수정하더라도 입력의 끝 부분으로 점프한다는 것을 알 수 있습니다.
그림 4: 편집할 때 중간 문제가 다시 발생합니다
위 그림에서 볼 수 있듯이 React는 중간부터 어떤 수정을 하더라도 커서를 맨 마지막에 위치시킵니다. 성능이 사용자의 기대에 미치지 못할 것입니다. 지속적인 입력을 할 수 없습니다. 이번에는 양쪽 끝의 동작이 일관되어 둘 다 예상치 못한 결과입니다. .
하지만 플랫폼에 따라 ifelse를 일부 작성할 필요가 없고 균일하게 처리할 수 있다는 장점이 있습니다. 위의 논의에서 우리는 React가 커서 위치를 저장하지 않는다는 것을 알 수 있습니다. 왜냐하면 이 동작을 지원하는 일반적이고 신뢰할 수 있는 알고리즘이 없기 때문입니다. 서식을 지정하기 위해 공백을 추가하거나 일부 문자를 필터링하거나 특정 조건을 트리거하고 다른 문자로 직접 변경하는 등 예측할 수 없는 변경으로 입력이 변경될 수 있기 때문입니다. 그러나 디지털 형식의 단일 시나리오에서는 커서 위치를 저장하는 논리가 훨씬 간단하고 명확해집니다.
在用户输入的过程中,只存在两种情况,在结尾中追加和在中间修改。在结尾追加的 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...
위 내용은 숫자 서식에서 React 입력의 커서를 처리하는 방법(자세히)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!