提问人:Ozge Cokyasar 提问时间:5/5/2019 更新时间:2/20/2023 访问量:65004
React - 如何将电话号码格式化为用户类型
React - How to format phone number as user types
问:
我需要将 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>
)
}
}```
答:
当前代码的正则表达式仅在输入十位数字(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
您必须处理这些情况中的每一种,而简单的替换是无法做到的。
我使用过这个库:https://www.npmjs.com/package/libphonenumber-js 它有一个 AsYouType 函数,您可以在输入上使用它
这一切都与格式有关。任何打印字符
的键都应导致输入字段的重写。
这样,无论用户做什么,他都只能看到有效的格式化字段。
正则表达式很简单^\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 - ____
等。。。(如果你想要这个,请告诉我)
评论
你可以喜欢这样normalize
input
- 是最新的
value
event.target.value
previousValue
是已验证并设置为state
其结构可防止无效字符更新输入,并将输入限制为 10 个数字。
单击下面的“运行代码段
”按钮以获取工作示例。
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>
评论
也许,以下内容对某人有用:
onChange={(e) => {
if (e.target.value.length < 13) {
var cleaned = ("" + e.target.value).replace(/\D/g, "");
let normValue = `${cleaned.substring(0, 3)}${
cleaned.length > 3 ? "-" : ""
}${cleaned.substring(3, 6)}${
cleaned.length > 6 ? "-" : ""
}${cleaned.substring(6, 11)}`;
handleChange(normValue);
}
}}
使用此包 https://www.npmjs.com/package/react-number-formatter 此输入组件格式化 number 并仅返回 number。
评论