React-如何将电话号码格式化为用户类型 [英] React - How to format phone number as user types

查看:67
本文介绍了React-如何将电话号码格式化为用户类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need to format a 10 digit string to this format: '(123) 456-7890'. However, I need this to happen as the user types. So if the user has inputted only 3 digits, the input should display: '(123)'. If they've inputted 5 digits the input should display: '(123) 45'

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

With my current code, the formatting only takes place after the 10th character is entered. I'd like it so that it formats it from the third character onwards.

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

推荐答案

您可以像这样normalize input

  • value是相对于event.target.value的最新信息
  • previousValue已被验证并设置为state
  • the value is up-to-date in relation to event.target.value
  • previousValue is what has already been validated and set to state

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

This is structured in a way to prevent invalid characters from updating the input and also limits the input to 10 numbers.

单击下面的Run code snippet按钮以查看工作示例.

Click the Run code snippet button below for a working example.

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个单独的输入,完成后将它们合并.

Or... have 3 separate inputs and combine them when done.

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>

这篇关于React-如何将电话号码格式化为用户类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆