简体   繁体   English

React Native:如何使用<TextInput />进行格式卡过期?

[英]React Native: How to make format card expiration with / using <TextInput/>?

In React Native using <TextInput/> , I am trying to make / appear only when the <TextInput/> is focused, and would stay there if another input is entered in. Currently, the format is MM/YY , so when the user types the third digit, it would go after the / , and if the user were to press back, it would delete the digit before the / . 在React Native中使用<TextInput/> ,我只是在<TextInput/>被聚焦时才会出现/出现,并且如果输入另一个输入则会保持在那里。目前,格式为MM/YY ,所以当用户键入第三个数字,它将在/ ,如果用户要按回,它将删除/之前的数字。

So what would be the right approach to implementing previously mentioned? 那么前面提到的实施方法是什么? Thank you and will be sure to accept the answer. 谢谢你,一定会接受答案。

I tried the following but getting an error with length, and this is only adding / after two digits have been entered: 我尝试了以下但是得到了一个长度错误,这只是在输入两位数后添加/

  _changeCardExpiry(value) {
    if (value.indexOf('.') >= 0 || value.length > 5) {
      return;
    }

    if (value.length === 2 && this.state.cardExpiry.length === 1) {
      value += '/'
    }

    //then update state cardExpiry
  }

  ...

  <TextInput
    onChangeText={this._changeCardExpiry.bind(this)}
    placeholder='MM/YY'
    value={cardExpiry}
  />

In formattion you actually need 3 functions one is for formatting the actual value, second is for converting formatted value back to actual value and the third is needed for checking whether the entered input so far can be valid or not. 在格式化中,您实际上需要3个函数,一个用于格式化实际值,第二个用于将格式化值转换回实际值,第三个用于检查到目前为止输入的输入是否有效。 For example for a date input entered letter inputs should be disregarded, but at the same time 99 should be disregarded as it is not a valid input for a month. 例如,对于日期输入,输入的字母输入应该被忽略,但同时99应该被忽略,因为它不是一个月的有效输入。 So for your specific case the following structure should work for you (in this example inputToValue function both checks whether the entered input is valid and set state according to it): 因此,对于您的特定情况,以下结构应该适用于您(在此示例中, inputToValue函数都检查输入的输入是否有效并根据它设置状态):

formatFunction(cardExpiry = ""){
   //expiryDate will be in the format MMYY, so don't make it smart just format according to these requirements, if the input has less than 2 character return it otherwise append `/` character between 2nd and 3rd letter of the input.
   if(cardExpiry.length < 2){
    return cardExpiry;
   }
   else{
    return cardExpiry.substr(0, 2) + "/" + (cardExpiry.substr(2) || "")
   }
}

inputToValue(inputText){
    //if the input has more than 5 characters don't set the state
    if(inputText.length < 6){
         const tokens = inputText.split("/");
         // don't set the state if there is more than one "/" character in the given input
         if(tokens.length < 3){
            const month = Number(tokens[1]);
            const year = Number(tokens[2]);
            //don't set the state if the first two letter is not a valid month
            if(month >= 1 && month <= 12){
               let cardExpiry = month + "";
               //I used lodash for padding the month and year with  zero               
               if(month > 1 || tokens.length === 2){
                    // user entered 2 for the month so pad it automatically or entered "1/" convert it to 01 automatically
                    cardExpiry = _.padStart(month, 2, "0");   
               }
               //disregard changes for invalid years
               if(year > 1 && year <= 99){
                   cardExpiry += year;
               }
               this.setState({cardExpiry});
            }
         }
    }
}

render(){
    let {cardExpiry} = this.state;
    return <TextInput
       value = {this.formatFunction(cardExpiry)}
       onChangeText={this.inputToValue.bind(this)}/>;
}

Not complete solution, but it solves similar problem - masking bluetooth address 不是完整的解决方案,但它解决了类似的问题 - 屏蔽蓝牙地址
AB
AB:C
AB:CD:EF:GH:IJ:KL

/*
Usage:
import { TextInput } from '../utils/input'
const MaskedTextInput = withMask(TextInput)
<MaskedTextInput
  placeholder="Printer address"
  value={ printerId }
  onChange={this.handlePrinterAddressChange}
/>
*/

import React, { Component } from 'react'
import { View } from 'react-native'

export const withMask = (WrappedComponent) => class Wrapper extends Component {

  constructor(props) {
    super()
    this.state = { value: props.value }
  }

  onChange(event) {
    let value = event.nativeEvent.text
    const rawValue = event.nativeEvent.text.replace(/:/g, '')

    if (rawValue) {
      value = rawValue.match(/.{1,2}/g).join(':').toUpperCase()
    }

    this.setState({value})

    if (this.props.onChange) {
      event.nativeEvent.text = value
      this.props.onChange(event)
    }
  }

  render() {
    return <WrappedComponent 
      {...this.props} 
      onChange={(event) => this.onChange(event)}
      value={this.state.value}
    />
  }

}

you can use this func from onChangeText; 你可以使用onChangeText中的这个func;

Don't forget to bind method inside constructor ; 不要忘记在构造函数中绑定方法;

this.fixCardText = this.fixCardText.bind(this)

fixCardText(text){
  if(text.length == 2 && this.state.text == 1){
    text += '/'
  }else if(text.length == 2 && this.state.text.length == 3){
    text = text.substring(0 , text.length-1)
  }
  this.setState({text:text}) 
}

your text input should be like; 你的文字输入应该是这样的;

<TextInput
  value = {this.state.text}
  onChangeText={(text)=>{this.fixCardText(text)}}
/>

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM