reactjs 在React中格式化数字时停止光标/插入符号跳跃

qv7cva1a  于 2023-06-05  发布在  React
关注(0)|答案(5)|浏览(272)

我在react组件上有一个输入字段,它显示了一个项目的行价格(小数点后两位,用千位分隔符)。我希望在组件首次呈现时显示的值是货币格式,并且在用户在字段中键入时保持货币格式。
目前,我的组件中有以下代码:

var React = require('react');
import accounting from 'accounting';
    
MoneyInput = React.createClass({
    propTypes: {
        name: React.PropTypes.string.isRequired,
        onChange: React.PropTypes.func.isRequired,
        value: React.PropTypes.number,
        error: React.PropTypes.string,
    },
    
    onChange(event) {
        // get rid of any money formatting
        event.target.value = accounting.unformat(event.target.value);
    
        // pass the value on
        this.props.onChange(event);
    },
    
    getValue() {
        return accounting.formatNumber(this.props.value, 2)
    },
    
    render() {
    
        return (
                <div className="field">
                    <input type="text"
                           name={this.props.name}
                           className="form-control"
                           value={this.getValue()}
                           onChange={this.onChange} />
                    <div className="input">{this.props.error}</div>
                </div>
        );
    }
});

module.exports = MoneyInput;

该代码显示了正确格式化的数据,但每次我输入一个值,光标/插入符号就会跳到数字的末尾。
我理解为什么会发生这种情况(我认为),我在这里读到了几个关于在JavaScript中不丢失光标位置的问题(例如herehere)。
我的问题是,在React中处理这个问题的最好方法是什么?
我认为理想情况下我不想将光标位置存储在状态(例如.我希望这些是Dan Abramov语法中的表示组件),那么还有其他方法吗?

qlckcl4x

qlckcl4x1#

在React的<input />字段中丢失光标/插入符号位置的一个简单的解决方案是自己管理位置:

onChange(event) {

      const caret = event.target.selectionStart
      const element = event.target
      window.requestAnimationFrame(() => {
        element.selectionStart = caret
        element.selectionEnd = caret
      })

      // your code
    }

光标位置重置的原因是因为React不知道你正在执行什么样的更改(如果你将文本完全更改为更短或更长的内容呢?),您现在负责控制插入符号的位置。

**示例:**在我的一个输入文本字段中,我自动将三个点(...)替换为省略号。前者是三个字符长的字符串,而后者只有一个字符。虽然React知道最终结果是什么,但它不知道该把光标放在哪里,因为没有一个明确的逻辑答案。

yptwkmov

yptwkmov2#

onKeyUp(ev) {
  const cardNumber = "8318 3712 31"
  const selectionStart = ev.target.selectionStart; // save the cursor position before cursor jump
  this.setState({ cardNumber, }, () => {
    ev.target.setSelectionRange(selectionStart, selectionStart); // set the cursor position on setState callback handler
  });
}
fjaof16o

fjaof16o3#

我认为我们可以在DOM级别上做到这一点。我所做的是向输入字段提供id。input元素中有一个属性selectionEnd。
您可以做的就是在normalize函数中获取input元素并获取其selectionEnd属性

const selectionEnd=inputElm &&inputElem.selectionEnd?inputElm.selectionEnd:0;

因为问题只在我们按下后退按钮时出现。我们添加一个条件如下

if(result.length<previousValue.length){
       inputElm.setSelectionRange(selectionEnd, selectionEnd)
    }

但是由于这个值将在我们从函数返回后被设置,并且返回的值将再次被设置,将光标推到末尾,所以我们只返回add一个settimeout。

setTimeout(() => {   
        if(result.length<previousValue.length){
            inputElm.setSelectionRange(selectionEnd, selectionEnd)
        }
    }, 50);

我今天刚刚遇到这个问题,似乎50个超时就足够了。
如果您想处理用户在中间添加数据的情况。下面的代码似乎运行良好。

if(result.length<previousValue.length){
         inputElm.setSelectionRange(selectionEnd, selectionEnd)
    } else if(selectionEnd!==result.length){ // result being the computed value
         inputElm.setSelectionRange(selectionEnd, selectionEnd)
    }
kmpatx3s

kmpatx3s4#

set value(val) { // Set by external method
        if(val != this.state.value) {
            this.setState({value: val, randKey: this.getKey()});
        }
    }

    getKey() {
        return 'input-key' + parseInt(Math.random() * 100000);
    }

    onBlur(e) {
        this.state.value = e.target.value; // Set by user
        if(this.props.blur) this.props.blur(e);
    }

    render() {
        return(
            <input className="te-input" type="text" defaultValue={this.state.value} onBlur={this.onBlur} key={this.state.randKey} />
        )
    }

如果你需要一个不需要光标移动就可以编辑的输入,并且可以从外部设置,你应该使用默认值,当外部改变值时,用不同的键呈现输入。

fd3cxomn

fd3cxomn5#

我有同样的问题,对我来说,这是因为我正在使用Redux。这篇文章真的解释得很好。
https://medium.com/@alutom/in-order-to-understand-what-is-really-happening-it-might-be-helpful-to-artificially-increase-the-e64ce17b70a6
浏览器管理输入光标,当它检测到一个新的文本时,它会自动将光标踢到最后,我猜状态会以触发浏览器行为的方式更新文本字段。

相关问题