
你可以
normalize在
input像现在这样
- 有关的
value
是最新的event.target.value
previousValue
是已经验证并设置为state
这种结构的结构可以防止无效字符更新输入,并将输入限制为10个数字。
单击Run pre 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-pre" 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-pre,.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>欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)