Le contenu de cet article explique comment gérer le curseur de la saisie React dans le formatage numérique (détails). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.
Ce dont nous allons parler aujourd'hui concerne certains comportements anormaux du curseur de saisie React et les solutions correspondantes dans des scénarios impliquant un formatage numérique. L'histoire commence par un problème. Certains utilisateurs ont signalé que lors de l'utilisation du composant NumberField pour la saisie, la position du curseur serait anormale sur Android, ce qui empêcherait la saisie continue d'obtenir les résultats escomptés. À quoi ressemble la performance spécifique ?
Figure 1 Comportement de saisie inattendu sous Android
Comme vous pouvez le voir, dans Every Le formatage de l'heure se produit sur un téléphone Android, le curseur qui doit toujours être à la fin sera au mauvais format, ce qui entraînera des problèmes de saisie continue. Ce problème n'apparaît pas sur PC Chrome ou iOS, il peut donc être déterminé comme étant un problème de compatibilité. Mais comment est né ce problème de compatibilité ?
Analysez le processus de formatage. Comme dans la situation ci-dessus, lors de la saisie de 18758, comme le numéro de carte doit être formaté, la valeur originale sera convertie en "1875 8", à partir de la longueur de la chaîne à partir du point ci-dessus. de vue, de 5 chiffres à 6 chiffres, si la position du curseur ne passe pas au dernier chiffre lorsque la valeur change, il restera dans l'espace. Il semblera qu'un mauvais chiffre soit saisi lors de la saisie continue. problèmes.
À en juger par le comportement de changement de curseur de la zone de saisie, cela ne semble pas être un changement anormal, il ne répond tout simplement pas au changement de valeur et saute jusqu'à la fin. Mais la question qui se pose est de savoir pourquoi cela va jusqu'au bout sur iOS et PC Chrome.
Figure 2 : Le même code se comporte différemment sous PC Chrome que sous Android.
J'ai donc cherché en ligne et trouvé un tel problème dans le github de React, le curseur passe à la fin de l'entrée contrôlée. Ici @sophiebits(spicyj), l'un des principaux responsables de React, a donné une réponse plus précise.
Figure 3, explication de Sophiebits sur le comportement du curseur lorsque la valeur d'entrée contrôlée par React change
Il s'avère que c'est à cause de la valeur Les changements sont très incertains, donc React ne peut pas utiliser une logique fiable et universelle pour enregistrer la position du curseur à une position appropriée, donc React déplacera le curseur vers la dernière position lors du nouveau rendu en mode contrôlé. Cela explique au moins pourquoi le curseur passe à la fin dans PC Chrome et iOS, mais je n'ai pas trouvé d'explication raisonnable pour laquelle Android n'affiche pas le même comportement.
Existe-t-il un moyen de rendre les performances sur Android cohérentes avec celles d'iOS ? Après un certain temps de lecture et d'essais, j'ai finalement découvert que si le processus de re-rendu et le onChange de l'entrée sont placés en deux ticks avant et après, les performances de l'entrée sous Android peuvent être cohérentes avec celles d'autres plates-formes. c'est-à-dire que le curseur sautera lors du nouveau rendu. À la fin, le code est le suivant.
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); }} /> ); } }
Cela rend enfin le comportement affiché cohérent sur Android et iOS, et les performances sont plus conformes aux attentes dans des conditions de saisie normales. Cependant, attendez, est-ce que ça va ? D'après les conclusions tirées dans le numéro précédent de React, nous pouvons voir que quelle que soit la manière dont la modification est effectuée, elle passera à la fin de l'entrée. Que se passera-t-il si elle est modifiée depuis le milieu ? 🎜>
Figure 4 : Un autre problème se produit lors de l'édition intermédiaire
Comme le montre l'image ci-dessus, car React changera le curseur quelles que soient les modifications apportées, à la fin, si vous le modifiez à partir du milieu, les performances ne répondront pas aux attentes de l'utilisateur et il n'y aura aucun moyen d'obtenir une saisie continue. Cette fois, le comportement des deux extrémités est cohérent, ce qui est tous deux inattendu. .
Mais il y a des avantages à ne pas être normal. Il n'est pas nécessaire d'écrire quelque chose d'autre en fonction de la plateforme, et cela peut être traité de manière uniforme. D'après la discussion ci-dessus, nous pouvons savoir que React n'enregistre pas la position du curseur car il n'existe aucun algorithme général et fiable pour prendre en charge ce comportement. En effet, l'entrée peut changer en ajoutant des espaces pour le formatage, en filtrant certains caractères ou en déclenchant certaines conditions et en passant directement à d'autres caractères, etc., ainsi que d'autres changements imprévisibles. Mais lorsqu’il s’agit du seul scénario de formatage numérique, la logique de sauvegarde de la position du curseur devient beaucoup plus simple et claire.在用户输入的过程中,只存在两种情况,在结尾中追加和在中间修改。在结尾追加的 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...
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!