小编典典

React-如何将电话号码格式化为用户类型

reactjs

我需要将10位数字的字符串格式设置为以下格式:’(123)456-7890’。但是,我需要在用户输入时发生这种情况。因此,如果用户仅输入了3位数字,则输入应显示:“(123)”。如果他们输入了5位数字,则输入内容应显示为:“(123)45”

使用我当前的代码,仅在输入第10个字符后才进行格式化。我希望它能从第三个字符开始对其进行格式化。

const phoneRegex = /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/

const handleInput = (value) => {
  return (
    value.replace(phoneRegex, '($1) $2-$3')
  )
}

class FindASubscriber extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      value: ''
    }
  }

  render() {
    const { label, placeholder, feedback } = this.props
    const { value} = this.state
    return (
      <div className="find__a__subscriber">
        <FlexGrid>
          <FlexGrid.Col>
            <FlexGrid.Row>
              <Input
                feedback={feedback}
                label={label}
                type="text"
                pattern="[0-9]*"
                placeholder={placeholder}
                value={handleInput(value)}
                maxLength="10"
                onChange={
                 (event) => this.setState({value: event.target.value})
                }
              />
            </FlexGrid.Row>
          </FlexGrid.Col>
        </FlexGrid>
      </div>
    )
  }
}```

阅读 247

收藏
2020-07-22

共1个答案

小编典典

你可以normalizeinput像现在这样

  • 有关的value是最新的event.target.value
  • previousValue 是已经验证并设置为 state

这种结构的结构可以防止无效字符更新输入,并将输入限制为10个数字。

单击Run code snippet下面的按钮以获取工作示例。


const normalizeInput = (value, previousValue) => {
  // return nothing if no value
  if (!value) return value;

  // only allows 0-9 inputs
  const currentValue = value.replace(/[^\d]/g, '');
  const cvLength = currentValue.length;

  if (!previousValue || value.length > previousValue.length) {

    // returns: "x", "xx", "xxx"
    if (cvLength < 4) return currentValue;

    // returns: "(xxx)", "(xxx) x", "(xxx) xx", "(xxx) xxx",
    if (cvLength < 7) return `(${currentValue.slice(0, 3)}) ${currentValue.slice(3)}`;

    // returns: "(xxx) xxx-", (xxx) xxx-x", "(xxx) xxx-xx", "(xxx) xxx-xxx", "(xxx) xxx-xxxx"
    return `(${currentValue.slice(0, 3)}) ${currentValue.slice(3, 6)}-${currentValue.slice(6, 10)}`; 
  }
};



const normalizeInput = (value, previousValue) => {

  if (!value) return value;

  const currentValue = value.replace(/[^\d]/g, '');

  const cvLength = currentValue.length;



  if (!previousValue || value.length > previousValue.length) {

    if (cvLength < 4) return currentValue;

    if (cvLength < 7) return `(${currentValue.slice(0, 3)}) ${currentValue.slice(3)}`;

    return `(${currentValue.slice(0, 3)}) ${currentValue.slice(3, 6)}-${currentValue.slice(6, 10)}`;

  }

};



const validateInput = value => {

  let error = ""



  if (!value) error = "Required!"

  else if (value.length !== 14) error = "Invalid phone format. ex: (555) 555-5555";



  return error;

};



class Form extends React.Component {

  constructor() {

    super();



    this.state = { phone: "", error: "" };

    this.handleChange = this.handleChange.bind(this);

    this.handleSubmit = this.handleSubmit.bind(this);

    this.handleReset = this.handleReset.bind(this);

  }



  handleChange({ target: { value } }) {

    this.setState(prevState=> ({ phone: normalizeInput(value, prevState.phone) }));

  };



  handleSubmit(e) {

    e.preventDefault();

    const error = validateInput(this.state.phone);



    this.setState({ error }, () => {

       if(!error) {

         setTimeout(() => {

           alert(JSON.stringify(this.state, null, 4));

         }, 300)

       }

    });

  }



  handleReset() {

     this.setState({ phone: "", error: "" });

  };



  render() {

    return(

      <form className="form" onSubmit={this.handleSubmit}>

        <div className="input-container">

          <p className="label">Phone:</p>

          <input

            className="input"

            type="text"

            name="phone"

            placeholder="(xxx) xxx-xxxx"

            value={this.state.phone}

            onChange={this.handleChange}

          />

          {this.state.error && <p className="error">{this.state.error}</p>}

        </div>

        <div className="btn-container">

          <button

             className="btn danger"

             type="button"

             onClick={this.handleReset}

           >

            Reset

          </button>

          <button className="btn primary" type="submit">Submit</button>

        </div>

      </form>

    );

  }

}



ReactDOM.render(

  <Form />,

  document.getElementById('root')

);


html {

  font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";

  font-size: 16px;

  font-weight: 400;

  line-height: 1.5;

  -webkit-text-size-adjust: 100%;

  background: #fff;

  color: #666;

}



.btn {

  color: #fff;

  border: 1px solid transparent;

  margin: 0 10px;

  cursor: pointer;

  text-align: center;

  box-sizing: border-box;

  padding: 0 30px;

  vertical-align: middle;

  font-size: .875rem;

  line-height: 38px;

  text-align: center;

  text-decoration: none;

  text-transform: uppercase;

  transition: .1s ease-in-out;

  transition-property: color,background-color,border-color;

}



.btn:focus {

  outline: 0;

}



.btn-container {

  text-align: center;

  margin-top: 10px;

}



.form {

  width: 550px;

  margin: 0 auto;

}



.danger {

  background-color: #f0506e;

  color: #fff;

  border: 1px solid transparent;

}



.danger:hover {

  background-color: #ee395b;

  color: #fff;

}



.error {

  margin: 0;

  margin-top: -20px;

  padding-left: 26%;

  color: red;

  text-align: left;

}



.input {

  display: inline-block;

  height: 40px;

  font-size: 16px;

  width: 70%;

  padding: 0 10px;

  background: #fff;

  color: #666;

  border: 1px solid #e5e5e5;

  transition: .2s ease-in-out;

  transition-property: color,background-color,border;

 }



.input-container {

  width: 100%;

  height: 60px;

  margin-bottom: 20px;

  display: inline-block;

}



.label {

  width: 25%;

  padding-top: 8px;

  display: inline-block;

  text-align: center;

  text-transform: uppercase;

  font-weight: bold;

  height: 34px;

  border-top-left-radius: 4px;

  border-bottom-left-radius: 4px;

  background: rgb(238, 238, 238);

}



.primary {

  background-color: #1e87f0;

}



.primary:hover {

  background-color: #0f7ae5;

  color: #fff;

}


<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>





<div id='root'>

</div>

或者…有3个单独的输入,完成后将它们合并。

const validateInput = value => {

  let error = ""



  if (!value) error = "Required!"

  else if (value.length !== 14) error = "Invalid phone format. ex: (555) 555-5555";



  return error;

};



const initialState = {

 areaCode: "",

 prefix: "",

 suffix: "",

 error: ""

};



class Form extends React.Component {

  constructor() {

    super();



    this.state = initialState;

    this.handleChange = this.handleChange.bind(this);

    this.handleSubmit = this.handleSubmit.bind(this);

    this.handleReset = this.handleReset.bind(this);

    this.setInputRef = this.setInputRef.bind(this);

  }



  handleChange({ target: { name, value } }) {

    let valueChanged = false;

    this.setState(prevState => {

      const nextValue = value.replace(/[^\d]/g, '');

      const changedValue = prevState[name];

      if (changedValue.length !== nextValue.length) valueChanged = true;



      return { [name]: nextValue }

    }, () => {

      if(valueChanged) this.handleFocus(name)

    });

  };



  setInputRef(name, element) {

   this[name] = element;

  }



  handleFocus(name){

    const { areaCode, prefix, suffix } = this.state;

    const areaCodeFilled = areaCode.length === 3;

    const prefixFilled = prefix.length === 3;



    if(areaCodeFilled && name === "areaCode") {

      this.prefix.focus();

      this.prefix.selectionEnd = 0;

    } else if(prefixFilled && name === "prefix") {

      this.suffix.focus();

      this.suffix.selectionEnd = 0;

    }

  }



  handleSubmit(e) {

    e.preventDefault();

    const { areaCode, prefix, suffix } = this.state;

    const phoneNumber = `(${areaCode}) ${prefix}-${suffix}`

    const error = validateInput(phoneNumber);



    this.setState({ error }, () => {

       if(!error) {

         setTimeout(() => {

           alert(phoneNumber);

         }, 300)

       }

    });

  }



  handleReset() {

     this.setState(initialState);

  };



  render() {

    return(

      <form className="form" onSubmit={this.handleSubmit}>

        <div className="input-container">

          <div className="label">

            Phone:

          </div>

          <div className="parenthesis" style={{ marginLeft: 10, marginRight: 2}}>&#40;</div>

          <input

            className="input area-code"

            type="text"

            name="areaCode"

            placeholder="xxx"

            value={this.state.areaCode}

            onChange={this.handleChange}

            maxLength="3"

          />

           <div className="parenthesis" style={{ marginRight: 2}}>&#41;</div>

          <input

            ref={node => this.setInputRef("prefix", node)}

            className="input prefix"

            type="text"

            name="prefix"

            placeholder="xxx"

            value={this.state.prefix}

            onChange={this.handleChange}

            maxLength="3"

          />

          <div className="dash">-</div>

          <input

            ref={node => this.setInputRef("suffix", node)}

            className="input suffix"

            type="text"

            name="suffix"

            placeholder="xxxx"

            value={this.state.suffix}

            onChange={this.handleChange}

            maxLength="4"

          />

        </div>

         <p className="error">{this.state.error}</p>

        <div className="btn-container">

          <button

             className="btn danger"

             type="button"

             onClick={this.handleReset}

           >

            Reset

          </button>

          <button className="btn primary" type="submit">Submit</button>

        </div>

      </form>

    );

  }

}



ReactDOM.render(

  <Form />,

  document.getElementById('root')

);


html {

  font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";

  font-size: 16px;

  font-weight: 400;

  line-height: 1.5;

  -webkit-text-size-adjust: 100%;

  background: #fff;

  color: #666;

}



.btn {

  color: #fff;

  border: 1px solid transparent;

  margin: 0 10px;

  cursor: pointer;

  text-align: center;

  box-sizing: border-box;

  padding: 0 30px;

  vertical-align: middle;

  font-size: .875rem;

  line-height: 38px;

  text-align: center;

  text-decoration: none;

  text-transform: uppercase;

  transition: .1s ease-in-out;

  transition-property: color,background-color,border-color;

}



.btn:focus {

  outline: 0;

}



.btn-container {

  text-align: center;

  margin-top: 10px;

}



.form {

  width: 550px;

  margin: 0 auto;

}



.danger {

  background-color: #f0506e;

  color: #fff;

  border: 1px solid transparent;

}



.danger:hover {

  background-color: #ee395b;

  color: #fff;

}



.error {

  margin: 0;

  height: 24px;

  margin-top: -20px;

  padding-left: 26%;

  color: red;

  text-align: right;

}



.input {

  display: flex;

  height: 40px;

  font-size: 16px;

  width: 33%;

  padding: 0 3px;

  background: #fff;

  color: #666;

  outline: none;

  border: 0;

}



.area-code,.prefix {

 width: 27px;

}



.suffix {

 width: 38px;

}



.dash,.parenthesis {

 display: flex;

}



.input-container {

  width: 100%;

  margin-bottom: 20px;

  display: flex;

  flex-direction: row;

  align-items: center;

  border-top-left-radius: 4px;

  border-bottom-left-radius: 4px;



    border: 1px solid #e5e5e5;

  transition: .2s ease-in-out;

  transition-property: color,background-color,borde

}



.label {

  height: 100%;

  background: rgb(238, 238, 238);

  width: 25%;

  padding-top: 8px;

  display: flex;

  text-transform: uppercase;

  justify-content: space-around;

  font-weight: bold;

  height: 34px;

}



.primary {

  background-color: #1e87f0;

}



.primary:hover {

  background-color: #0f7ae5;

  color: #fff;

}


<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>





<div id='root'>

</div>
2020-07-22