使用 React,如何绑定到用户的剪贴板粘贴事件和解析数据?
With React, how to bind to the user's clipboard paste event and parse data?
我需要构建一个电子邮件验证,需要将代码发送到用户的电子邮件地址。与 Slack 在其注册流程中处理电子邮件验证的方式非常相似:
粘贴时,粘贴的文本会一个接一个地输入。对于 React,实现这样的功能的正确方法是什么?
在componentDidMount之后,我应该绑定并捕获粘贴keyPress吗?这是正确的做法吗?
超级简单的示例,让您朝着正确的方向开始。这在使用之前需要做一些工作。这是它的作用:
- 允许用户粘贴代码并用值填充每个输入
- 允许用户输入代码
- 允许用户编辑代码
- 当用户输入一个值时,它会将焦点转移到下一个输入
- 只允许数字输入
- 每个输入只允许一个数字
这里没有什么特别棘手的。为了示例,我们使用本地状态,但这可以转移到另一个状态管理实现,如 Redux。
该演示使用两个组件:
<Input />
- 呈现受控输入
<App />
为 <Input />
呈现一个容器
<App />
组件处理 onPaste
事件,并将粘贴数据中的适当值传递给每个 <Input />
组件
每个 <Input />
组件包含一个受控的 <input/>
元素,该元素仅包含一个 value
.
// A functional component to keep it simple
class Input extends React.Component {
constructor(props) {
super(props);
this.state = {
value: ''
};
}
handleKeyDown = (event) => {
// Handle the delete/backspace key
if (event.keyCode === 8 || event.keyCode === 46) {
this.setState({
value: ''
});
return;
}
// Handle the tab key
if (event.keyCode === 9) {
return;
}
// Handle numbers and characters
const key = String.fromCharCode(event.which);
if (Number.isInteger(Number(key))) {
this.setState({
value: key
}, () => {
// Move focus to next input
this.refs[(this.props.index + 1) % 6].focus()
});
}
}
componentWillReceiveProps = (nextProps) => {
if (nextProps.value !== this.state.value) {
this.setState({
value: nextProps.value
})
}
}
render() {
return (
<div className="inputContainer">
<input
className="input"
value={this.state.value}
onKeyDown={this.handleKeyDown}
ref={(ref) => this.refs[this.props.index] = ref}
maxLength="1"
/>
</div>
)
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
code: null
}
}
handlePaste = (event) => {
event.clipboardData.items[0].getAsString(text => {
const code = text.split("").map((char, index) => {
if (Number.isInteger(Number(char))) {
return Number(char);
}
return "";
});
this.setState({
code
});
})
}
render() {
const code = this.state.code;
return (
<div className="container" onPaste={this.handlePaste}>
<Input value={code && code[0]} index={0} />
<Input value={code && code[1]} index={1} />
<Input value={code && code[2]} index={2} />
<div className="spacer">-</div>
<Input value={code && code[3]} index={3} />
<Input value={code && code[4]} index={4} />
<Input value={code && code[5]} index={5} />
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById("app"));
.container {
display: flex;
}
.inputContainer {
flex: 1;
border: 1px solid #cccccc;
}
.inputContainer:last-child {
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.inputContainer:first-child {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
.spacer {
flex: 0.3 0;
text-align: center;
height: 40px;
line-height: 40px;
font-size: 24px;
}
.input {
width: 100%;
height: 40px;
line-height: 40px;
font-size: 24px;
text-align: center;
border: none;
outline: none;
border-radius: 5px;
box-sizing: border-box;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Test Code: 135791
<div id="app"></div>
我需要构建一个电子邮件验证,需要将代码发送到用户的电子邮件地址。与 Slack 在其注册流程中处理电子邮件验证的方式非常相似:
粘贴时,粘贴的文本会一个接一个地输入。对于 React,实现这样的功能的正确方法是什么?
在componentDidMount之后,我应该绑定并捕获粘贴keyPress吗?这是正确的做法吗?
超级简单的示例,让您朝着正确的方向开始。这在使用之前需要做一些工作。这是它的作用:
- 允许用户粘贴代码并用值填充每个输入
- 允许用户输入代码
- 允许用户编辑代码
- 当用户输入一个值时,它会将焦点转移到下一个输入
- 只允许数字输入
- 每个输入只允许一个数字
这里没有什么特别棘手的。为了示例,我们使用本地状态,但这可以转移到另一个状态管理实现,如 Redux。
该演示使用两个组件:
<Input />
- 呈现受控输入<App />
为<Input />
呈现一个容器
<App />
组件处理 onPaste
事件,并将粘贴数据中的适当值传递给每个 <Input />
组件
每个 <Input />
组件包含一个受控的 <input/>
元素,该元素仅包含一个 value
.
// A functional component to keep it simple
class Input extends React.Component {
constructor(props) {
super(props);
this.state = {
value: ''
};
}
handleKeyDown = (event) => {
// Handle the delete/backspace key
if (event.keyCode === 8 || event.keyCode === 46) {
this.setState({
value: ''
});
return;
}
// Handle the tab key
if (event.keyCode === 9) {
return;
}
// Handle numbers and characters
const key = String.fromCharCode(event.which);
if (Number.isInteger(Number(key))) {
this.setState({
value: key
}, () => {
// Move focus to next input
this.refs[(this.props.index + 1) % 6].focus()
});
}
}
componentWillReceiveProps = (nextProps) => {
if (nextProps.value !== this.state.value) {
this.setState({
value: nextProps.value
})
}
}
render() {
return (
<div className="inputContainer">
<input
className="input"
value={this.state.value}
onKeyDown={this.handleKeyDown}
ref={(ref) => this.refs[this.props.index] = ref}
maxLength="1"
/>
</div>
)
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
code: null
}
}
handlePaste = (event) => {
event.clipboardData.items[0].getAsString(text => {
const code = text.split("").map((char, index) => {
if (Number.isInteger(Number(char))) {
return Number(char);
}
return "";
});
this.setState({
code
});
})
}
render() {
const code = this.state.code;
return (
<div className="container" onPaste={this.handlePaste}>
<Input value={code && code[0]} index={0} />
<Input value={code && code[1]} index={1} />
<Input value={code && code[2]} index={2} />
<div className="spacer">-</div>
<Input value={code && code[3]} index={3} />
<Input value={code && code[4]} index={4} />
<Input value={code && code[5]} index={5} />
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById("app"));
.container {
display: flex;
}
.inputContainer {
flex: 1;
border: 1px solid #cccccc;
}
.inputContainer:last-child {
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.inputContainer:first-child {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
.spacer {
flex: 0.3 0;
text-align: center;
height: 40px;
line-height: 40px;
font-size: 24px;
}
.input {
width: 100%;
height: 40px;
line-height: 40px;
font-size: 24px;
text-align: center;
border: none;
outline: none;
border-radius: 5px;
box-sizing: border-box;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Test Code: 135791
<div id="app"></div>