Реагировать - Как отформатировать номер телефона как типы пользователей - PullRequest
1 голос
/ 05 мая 2019

Мне нужно отформатировать 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>
    )
  }
}```

Ответы [ 4 ]

1 голос
/ 05 мая 2019

Регулярное выражение вашего текущего кода совпадает только при вводе десяти цифр (3, 3, затем 4). Вы можете обновить регулярное выражение, чтобы принимать диапазон цифр, таких как:

^\(?([0-9]{0,3})\)?[-. ]?([0-9]{0,3})[-. ]?([0-9]{0,4})$

Или вы можете задать регулярное выражение, просто убедившись, что введены цифры 0-10 ([0-9] {0,10}), а затем разбить строку самостоятельно на подстроки длины 3, 3 и 4. Выполнение этого последний способ выглядит лучше, поскольку вы хотите отображать только определенные символы в зависимости от того, сколько цифр введено пользователем:

1 -> (1

123 -> (123)

1234567 -> (123) 456-7

1234567890 -> (123) 456-7890

Вы должны были бы обработать каждый из этих случаев, чего не подойдет простая замена.

0 голосов
/ 05 мая 2019

Вы можете normalize input, как и так

  • 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, ''); 

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

    // returns: "x", "xx", "xxx"
    if (currentValue.length <= 3) return currentValue; 

    // returns: "(xxx)"
    if (currentValue.length === 3) return `(${currentValue})`; 

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

    // returns: "(xxx) xxx-"
    if (currentValue.length === 6) return `(${currentValue.slice(0, 3)}) ${currentValue.slice(3)}-` 

    // returns: "(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, '');
  if (!previousValue || value.length > previousValue.length) {
    if (currentValue.length <= 3) return currentValue;
    if (currentValue.length === 3) return `(${currentValue})`;
    if (currentValue.length <= 6) return `(${currentValue.slice(0, 3)}) ${currentValue.slice(3)}`;
    if (currentValue.length === 6) 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 } }) {
    const normalized = normalizeInput(value, this.state.phone);
    
    this.setState({ phone: normalized });
  };
  
  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>
0 голосов
/ 05 мая 2019

Это все о форматировании. Любая клавиша, которая печатает символ
должно вызвать перезапись поля ввода.
Таким образом, пользователь видит только правильное отформатированное поле, независимо от того, что он делает.

регулярное выражение просто ^\D*(\d{0,3})\D*(\d{0,3})\D*(\d{0,4})

function getFormattedPhoneNum( input ) {
  let output = "(";
  input.replace( /^\D*(\d{0,3})\D*(\d{0,3})\D*(\d{0,4})/, function( match, g1, g2, g3 )
      {
        if ( g1.length ) {
          output += g1;
          if ( g1.length == 3 ) {
              output += ")";
              if ( g2.length ) {
                  output += " " + g2; 
                  if ( g2.length == 3 ) {
                      output += " - ";
                      if ( g3.length ) {
                          output += g3;
                      }
                  }
              }
           }
        }
      }       
    );        
  return output;
 }       

console.log( getFormattedPhoneNum("") );
console.log( getFormattedPhoneNum("2") );
console.log( getFormattedPhoneNum("asdf20as3d") );
console.log( getFormattedPhoneNum("203") );
console.log( getFormattedPhoneNum("203-44") );
console.log( getFormattedPhoneNum("444sg52asdf22fd44gs") );
console.log( getFormattedPhoneNum("444sg526sdf22fd44gs") );
console.log( getFormattedPhoneNum("444sg526sdf2244gs") );
console.log( getFormattedPhoneNum(" ra098 848 73653k-atui ") );

Вы даже можете полюбоваться и показать подчеркивание, где персонаж
должно быть в любой момент времени.
Как
(___) ___ - ____
(20_) ___ - ____
(123) 456 - ____

и т.д ... (дайте мне знать, если хотите)

0 голосов
/ 05 мая 2019

Я использовал эту библиотеку: https://www.npmjs.com/package/libphonenumber-js она имеет функцию AsYouType, которую вы можете использовать на своих входах

...