我需要将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> ) } }```
你可以normalize在input像现在这样
normalize
input
value
event.target.value
previousValue
state
这种结构的结构可以防止无效字符更新输入,并将输入限制为10个数字。
单击Run code snippet下面的按钮以获取工作示例。
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}}>(</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}}>)</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>