簡體   English   中英

拒絕輸入時插入符號跳到結尾

[英]Caret Jumping to End When Rejecting Input

我有一個值的輸入。 我想驗證用戶輸入的新值,並防止該值在無效時出現在輸入中。 例如,值應該是數字,因此只能包含數字、點和逗號。

我有一個驗證 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
}

在我的輸入字段中,我調用了一個自定義的handleChange function,它確保新輸入在存儲到 state 變量之前是有效的。

渲染輸入

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

處理輸入變化

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

如果插入了無效輸入並且驗證失敗,則我的輸入字段中的值不會更改(如預期的那樣),但插入符號會跳轉到輸入字段的末尾(不可取)。


嘗試的解決方案

我試圖通過采用這個答案來修復插入符號跳躍行為,其中我創建了一個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} />
    )
}

使用此解決方案,插入符號在第一次輸入無效值時保持在正確的 position 處,但隨着我繼續按下相同的鍵,一遍又一遍地插入無效值,在第一次之后,插入符號移回末尾的輸入。 這是因為 useEffect 沒有被調用第二次和后續的時間。

無論用戶嘗試插入無效值多少次,我如何才能使插入符號始終保持在相同的 position 上?

更新:-

對不起,我的不好,我沒有完全看這個問題。 但是,我所說的也是正確的,但在當前情況下並非如此。 請在下面找到更新的代碼。 下面的代碼也應該更高效,因為它不涉及每次更改的重新渲染

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>
  );
}

我也在播放代碼代碼鏈接上進行了相同的更改

React 在 setstate 調用時重新渲染整個組件。 在您的情況下,值將被保留,因為它是受控輸入。 但在幕后 React 基本上是在每次輸入值時創建一個新的輸入字段。 強制做出反應以使用具有恆定值的相同字段傳遞鍵道具。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM