使用5个输入文本

时间:2018-01-30 10:37:41

标签: react-native

我是新手做出反应原生的,所以我可能会采取错误的做法,如果有的话,请随意指出更好的架构。

我正在构建一个显示5个InputText的组件。每个都只能有一个数字,所以当文本改变时,我使用onChangeText事件继续下一个TextInput。 我遇到的问题是如何设置当前关注的TextInput的样式。我将onFocus和onBlur事件触发,但是当我为样式设置state时,没有任何反应。

以下是代码:

class DigitFramedControl extends React.Component<
  {},
  { showingError: boolean, errorString: string, value: string, backgroundColor: string },
> {
  constructor(props: {}) {
    super(props);

    this.state = {
      showingError: false,
      errorString: 'Votre réponse est erroné. Veuillez réessayer.',
      value: '     ',
    };
  }

  handleDigitChanged(index: number, character: string) {
    if (index > this.state.value.length) {
      const error = new Error('index out of range');
      throw error;
    } else if (character.length === 0) {
      // user pressed backspace, don't change the end value
      // the digit is updated in the text input though
    } else {
      console.log('setting state');
      this.setState((prevState, props) => ({
        value: prevState.value.substr(0, index) + character + prevState.value.substr(index + 1),
      }));

      // go to next field
      if (index < 4) {
        this.digitTextInputAtIndex(index + 1).focus();
      }
    }
  }

  onDigitFocus = (index: number) => {
    const textInput = this.digitTextInputAtIndex(index);
    // this.style = [styles.digitFramedControlDigit, { backgroundColor: 'green' }];
    textInput.setState({ style: [styles.digitFramedControlDigit, { backgroundColor: 'green' }] });
  };

  onDigitBlur = (index: number) => {
    const textInput = this.digitTextInputAtIndex(index);
    // this.style = [styles.digitFramedControlDigit, { backgroundColor: 'green' }];
    textInput.setState({ style: [styles.digitFramedControlDigit, { backgroundColor: 'red' }] });
    // this.style = [styles.digitFramedControlDigit, { backgroundColor: 'red' }];
  };

  digitTextInputAtIndex: TextInput = (index) => {
    let returnValue = null;
    switch (index) {
      case 0:
        returnValue = this.refs.digit0;
        break;
      case 1:
        returnValue = this.refs.digit1;
        break;
      case 2:
        returnValue = this.refs.digit2;
        break;
      case 3:
        returnValue = this.refs.digit3;
        break;
      case 4:
        returnValue = this.refs.digit4;
        break;
    }

    return returnValue;
  };

  render() {
    const sharedTextInputProps = {
      maxLength: 1,
      selectTextOnFocus: true,
      selectionColor: '#ffffff00',
      autoCapitalize: 'none',
    };
    return (
      <View
        style={{
          flexDirection: 'column',
          height: 100,
          width: 300,
          borderWidth: 1,
          borderColor: '#090',
        }}
      >
        <View
          style={{
            flex: 1,
            flexDirection: 'row',
            justifyContent: 'space-between',
            borderWidth: 1,
            borderColor: '#600',
          }}
        >
          <TextInput
            {...sharedTextInputProps}
            ref="digit0"
            onChangeText={this.handleDigitChanged.bind(this, 0)}
            onFocus={this.onDigitFocus.bind(this, 0)}
            onBlur={this.onDigitBlur.bind(this, 0)}
            style={[
              styles.digitFramedControlDigit,
              { backgroundColor: this.state.backgroundColor },
            ]}
            returnKeyType="next"
          />
          <TextInput
            ref="digit1"
            style={styles.digitFramedControlDigit}
            onChangeText={this.handleDigitChanged.bind(this, 1)}
            returnKeyType="next"
            onFocus={this.onDigitFocus.bind(this, 1)}
            onBlur={this.onDigitBlur.bind(this, 1)}
            style={[
              styles.digitFramedControlDigit,
              { backgroundColor: this.state.backgroundColor },
            ]}
          />
          <TextInput
            ref="digit2"
            style={styles.digitFramedControlDigit}
            onChangeText={this.handleDigitChanged.bind(this, 2)}
            onFocus={this.onDigitFocus.bind(this, 2)}
            onBlur={this.onDigitBlur.bind(this, 2)}
            style={[
              styles.digitFramedControlDigit,
              { backgroundColor: this.state.backgroundColor },
            ]}
            returnKeyType="next"
          />
          <TextInput
            ref="digit3"
            style={styles.digitFramedControlDigit}
            onChangeText={this.handleDigitChanged.bind(this, 3)}
            onFocus={this.onDigitFocus.bind(this, 3)}
            onBlur={this.onDigitBlur.bind(this, 3)}
            returnKeyType="next"
          />
          <TextInput
            ref="digit4"
            style={styles.digitFramedControlDigit}
            onChangeText={this.handleDigitChanged.bind(this, 4)}
            onFocus={this.onDigitFocus.bind(this, 4)}
            onBlur={this.onDigitBlur.bind(this, 4)}
            returnKeyType="done"
          />
        </View>
        <Text style={styles.digitFrameErrorString}>{this.state.errorString}</Text>
        <Text style={styles.digitFrameErrorString}>{this.state.value}</Text>
      </View>
    );
  }
}

1 个答案:

答案 0 :(得分:1)

查看以下代码。

基本上,它将焦点字段的索引存储为focusedInput状态。

然后,当将样式应用于每个Input时,如果索引与聚焦索引匹配,它会有条件地应用绿色背景颜色。

注意:代码未经测试,因此需要语法错误等等!

我还重构了digitTextInputAtIndex以大大简化它;)

class DigitFramedControl extends React.Component<
  {},
  { showingError: boolean, errorString: string, value: string, backgroundColor: string },
> {
  constructor(props: {}) {
    super(props);

    this.state = {
      showingError: false,
      errorString: 'Votre réponse est erroné. Veuillez réessayer.',
      value: '     ',
      focusedInput: null,
    };
  }

  handleDigitChanged(index: number, character: string) {
    if (index > this.state.value.length) {
      const error = new Error('index out of range');
      throw error;
    } else if (character.length === 0) {
      // user pressed backspace, don't change the end value
      // the digit is updated in the text input though
    } else {
      console.log('setting state');
      this.setState((prevState, props) => ({
        value: prevState.value.substr(0, index) + character + prevState.value.substr(index + 1),
      }));

      // go to next field
      if (index < 4) {
        this.digitTextInputAtIndex(index + 1).focus();
      }
    }
  }

  onDigitFocus = (index: number) => {
    this.setState({ focusedInput: index })
  };

  onDigitBlur = (index: number) => {
    this.setState({ focusedInput: null })
  };

  digitTextInputAtIndex: TextInput = (index) => {
    return this.refs[`digit${index}`]
  };

  render() {
    const sharedTextInputProps = {
      maxLength: 1,
      selectTextOnFocus: true,
      selectionColor: '#ffffff00',
      autoCapitalize: 'none',
    };
    return (
      <View
        style={{
          flexDirection: 'column',
          height: 100,
          width: 300,
          borderWidth: 1,
          borderColor: '#090',
        }}
      >
        <View
          style={{
            flex: 1,
            flexDirection: 'row',
            justifyContent: 'space-between',
            borderWidth: 1,
            borderColor: '#600',
          }}
        >
          <TextInput
            {...sharedTextInputProps}
            ref="digit0"
            onChangeText={this.handleDigitChanged.bind(this, 0)}
            onFocus={this.onDigitFocus.bind(this, 0)}
            onBlur={this.onDigitBlur.bind(this, 0)}
            style={[
              styles.digitFramedControlDigit,
              this.state.focusedInput === 0 && { backgroundColor: 'green' }
            ]}
            returnKeyType="next"
          />
          <TextInput
            ref="digit1"
            onChangeText={this.handleDigitChanged.bind(this, 1)}
            returnKeyType="next"
            onFocus={this.onDigitFocus.bind(this, 1)}
            onBlur={this.onDigitBlur.bind(this, 1)}
            style={[
              styles.digitFramedControlDigit,
              this.state.focusedInput === 1 && { backgroundColor: 'green' }
            ]}
          />
          <TextInput
            ref="digit2"
            onChangeText={this.handleDigitChanged.bind(this, 2)}
            onFocus={this.onDigitFocus.bind(this, 2)}
            onBlur={this.onDigitBlur.bind(this, 2)}
            style={[
              styles.digitFramedControlDigit,
              this.state.focusedInput === 2 && { backgroundColor: 'green' }
            ]}
            returnKeyType="next"
          />
          <TextInput
            ref="digit3"
            onChangeText={this.handleDigitChanged.bind(this, 3)}
            onFocus={this.onDigitFocus.bind(this, 3)}
            onBlur={this.onDigitBlur.bind(this, 3)}
            style={[
              styles.digitFramedControlDigit,
              this.state.focusedInput === 3 && { backgroundColor: 'green' }
            ]}
            returnKeyType="next"
          />
          <TextInput
            ref="digit4"
            onChangeText={this.handleDigitChanged.bind(this, 4)}
            onFocus={this.onDigitFocus.bind(this, 4)}
            onBlur={this.onDigitBlur.bind(this, 4)}
            style={[
              styles.digitFramedControlDigit,
              this.state.focusedInput === 4 && { backgroundColor: 'green' }
            ]}
            returnKeyType="done"
          />
        </View>
        <Text style={styles.digitFrameErrorString}>{this.state.errorString}</Text>
        <Text style={styles.digitFrameErrorString}>{this.state.value}</Text>
      </View>
    );
  }
}