简体   繁体   English

拒绝输入时插入符号跳到结尾

[英]Caret Jumping to End When Rejecting Input

I have an input for a value.我有一个值的输入。 I want to validate the new value entered by the user and prevent the value from appearing in the input if it's invalid.我想验证用户输入的新值,并防止该值在无效时出现在输入中。 For instance, the value should be numeric, and hence can only contain numbers, dots, and commas.例如,值应该是数字,因此只能包含数字、点和逗号。

I have a validation function which returns true / false depending on whether a value meets the criteria (works as intended):我有一个验证 function 根据值是否符合标准(按预期工作)返回true / false

function validateInput(input) {
    let allow = true
    const splitValuesByDecimal = input.split(',')
        
    if(allow) allow = /^[\d|,|.]*?$/.test(input) // allow only digits, dots, and commas
    if(allow) allow = splitValuesByDecimal.length <= 2 // allow only 1 decimal separator (comma)
    if(allow && splitValuesByDecimal.length > 1) allow = splitValuesByDecimal.at(-1).length <= 2 // allow only maximum of 2 decimal characters
    return allow
}

In my input field, I call a custom handleChange function which ensures that the new input is valid before storing it in the state variable.在我的输入字段中,我调用了一个自定义的handleChange function,它确保新输入在存储到 state 变量之前是有效的。

Rendering input渲染输入

<input value={inputVal} onChange={handleChange} />

Handling input change处理输入变化

function handleChange(e) {
    const value = e.target.value
    if(validateInput(value)) {
        setInputVal(value)
    }
}

If an invalid input is inserted and validation fails, the value in my input field does not change (as intended), but the caret jumps to the end of the input field (not desirable).如果插入了无效输入并且验证失败,则我的输入字段中的值不会更改(如预期的那样),但插入符号会跳转到输入字段的末尾(不可取)。


Attempted Solution尝试的解决方案

I have tried to fix the caret jumping behaviour by adopting this answer where I created a cursor state variable which keeps track of the intended caret position:我试图通过采用这个答案来修复插入符号跳跃行为,其中我创建了一个cursor state 变量,该变量跟踪预期的插入符号 position:

function MyComponent() {

    const [inputVal, setInputVal] = useState('')
    const [cursor, setCursor] = useState(null)
    const inputRef = useRef()

    useEffect(() => {
        if (inputRef.current) inputRef.current.setSelectionRange(cursor, cursor);
    }, [inputRef, cursor, inputVal])

    function validateInput(input) {
        ...
    }

    function handleChange(e) {
        const value = e.target.value
        if(validateInput(value)) {
            setCursor(e.target.selectionStart)
            setInputVal(value)
        }
        else {
            setCursor(e.target.selectionStart - 1)
        }
    }

    return (
        <input 
            ref={inputRef}
            value={inputVal} 
            onChange={handleChange} />
    )
}

With this solution, the caret persists at the correct position the first time an invalid value is entered, but as I keep on subsequently pressing the same key inserting invalid value over and over again, after the first time, the caret moves back to the end of the input.使用此解决方案,插入符号在第一次输入无效值时保持在正确的 position 处,但随着我继续按下相同的键,一遍又一遍地插入无效值,在第一次之后,插入符号移回末尾的输入。 This is because the useEffect is not called the second and subsequent times.这是因为 useEffect 没有被调用第二次和后续的时间。

How can I make this work so that caret always stays at the same position regardless of how many times the user attempts to insert an invalid value?无论用户尝试插入无效值多少次,我如何才能使插入符号始终保持在相同的 position 上?

Update:-更新:-

Sorry my bad, I haven't looked at the question completely.对不起,我的不好,我没有完全看这个问题。 However what I was saying is also correct but not in current case.但是,我所说的也是正确的,但在当前情况下并非如此。 Please find the updated code below.请在下面找到更新的代码。 Below code should also be more performant as it does not involve re-renders on every change下面的代码也应该更高效,因为它不涉及每次更改的重新渲染

import React, { useState, useRef } from 'react';

export function App(props) {
  const inputRef = useRef()
  const oldVal = useRef(null)

  function validateInput(input) {
    let allow = true
    const splitValuesByDecimal = input.split(',')

    if(allow) allow = /^[\d|,|.]*?$/.test(input) // allow only digits, dots, and commas
    if(allow) allow = splitValuesByDecimal.length <= 2 // allow only 1 decimal separator (comma)
    if(allow && splitValuesByDecimal.length > 1) allow = splitValuesByDecimal.at(-1).length <= 2 // allow only maximum of 2 decimal characters
    console.log(allow)
    return allow
  }

  function handleChange(e) {
        const valueNew = e.target.value
        const pos = e.target.selectionStart - 1
        if(validateInput(valueNew)) {
            oldVal.current = valueNew
        } else {
          inputRef.current.value = oldVal.current
          inputRef.current.setSelectionRange(pos, pos)
        }
    }

  return (
    <div key='mydiv' className='App'>
      <input key='MyFixedKeyValue' ref={inputRef} onChange={handleChange} />
    </div>
  );
}

I also changed the same on playcode code link我也在播放代码代码链接上进行了相同的更改

React re-renders the whole component on setstate call. React 在 setstate 调用时重新渲染整个组件。 In your case values are being kept as it is a controlled input.在您的情况下,值将被保留,因为它是受控输入。 But behind the scene react is basically creating a new input field every time you are entering a value.但在幕后 React 基本上是在每次输入值时创建一个新的输入字段。 To force react to use the same field pass key prop with constant value.强制做出反应以使用具有恒定值的相同字段传递键道具。

<input 
        key='MyFixedKeyValue'
        ref={inputRef}
        value={inputVal} 
        onChange={handleChange} />

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 确定插入符号何时到达输入框的末尾 - Determine when caret reaches the end of input box 为什么我的 Contenteditable 插入符在 Chrome 中跳到最后? - Why Is My Contenteditable caret Jumping to the End in Chrome? 当插入符号在其末尾的输入内部时,在输入后立即移动插入符号 - Move caret right after input in contenteditable when caret is inside the input at the end of it 单击反应时如何将光标/插入符号移动到输入的末尾 - how to move cursor/caret to end of input when clicked in react 如何阻止 cursor 跳到输入结束 - How to stop cursor from jumping to the end of input 如何在原始文本中间粘贴HTML单词后,防止插入符号在contenteditable div中跳到整个文本的末尾? - How to prevent the caret jumping to the end of the whole text in contenteditable div after pasting the HTML words in the middle of the original text? 将插入符号移动到文本输入字段的末尾并使结尾可见 - Move caret to the end of a text input field AND make the end visible IE 8:将插入符号移至文本输入字段的末尾并使末尾可见 - IE 8: move caret to the end of a text input field AND make the end visible Chrome与removeChild一起跳跃插入符号错误 - Chrome jumping caret bug with removeChild 停止插入跳到textarea的底部? - Stop caret jumping to bottom of textarea?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM