我需要从Material-ui的TextField获取文本选择数据。文本选择数据必须包括选择开始,选择结束和选择的文本。
我使用createRefs设法达到了以下目标
import React, { createRef } from "react";
import { TextField, Button, Box, Grid } from "@material-ui/core";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
selStart: undefined,
selEnd: undefined,
selValue: undefined
};
this.onSaveSelectionClicked = this.onSaveSelectionClicked.bind(this);
this.textFieldRef = createRef();
}
onSaveSelectionClicked(ev) {
// Somehow obtain selection start, end, and value
// then update state
const { selectionStart, selectionEnd, value } = this.textFieldRef.current;
this.setState({
selStart: selectionStart,
selEnd: selectionEnd,
selValue: value.substring(selectionStart, selectionEnd)
});
}
render() {
return (
<Box p="2em">
<Grid container spacing={2}>
<Grid item xs={12}>
<TextField
name="essay1"
label="Essay 1"
multiline
rows={3}
fullWidth
inputRef={this.textFieldRef}
/>
</Grid>
<Grid item xs={12}>
<TextField
name="essay2"
label="Essay 2"
multiline
rows={3}
fullWidth
inputRef={this.textFieldRef}
/>
</Grid>
<Grid item xs={12}>
<Button variant="contained" onClick={this.onSaveSelectionClicked}>
Save selection
</Button>
</Grid>
<Grid item xs={12}>
<pre>{JSON.stringify(this.state)}</pre>
</Grid>
</Grid>
</Box>
);
}
}
哪个给我以下内容
问题是,这似乎不适用于多个TextField。引用的current
属性将始终引用“论文2”文本字段。
有没有更好的方法来解决这个问题?
以下是上述代码的指向codesandbox的链接
答案 0 :(得分:2)
完全不需要引用,因此选择会动态更改。
更改构造函数,如下所示:
constructor(props) {
super(props);
this.state = {
selStart: undefined,
selEnd: undefined,
selValue: undefined
};
this.onSelectionChange = this.onSelectionChange.bind(this);
}
添加处理程序:
onSelectionChange(e) {
const { selectionStart, selectionEnd, value } = e.target;
this.setState({
selStart: selectionStart,
selEnd: selectionEnd,
selValue: value.substring(selectionStart, selectionEnd)
});
}
然后在您的文本字段中,只需将事件设置为onMouseUp(或onBlur,如果您想更新lostFocus):
onMouseUp={this.onSelectionChange}
执行此操作的源代码如下:
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
selStart: undefined,
selEnd: undefined,
selValue: undefined
};
this.onSelectionChange = this.onSelectionChange.bind(this);
}
onSelectionChange(e) {
const { selectionStart, selectionEnd, value } = e.target;
this.setState({
selStart: selectionStart,
selEnd: selectionEnd,
selValue: value.substring(selectionStart, selectionEnd)
});
}
render() {
return (
<Box p="2em">
<Grid container spacing={2}>
<Grid item xs={12}>
<TextField
name="essay1"
label="Essay 1"
multiline
rows={3}
fullWidth
onMouseUp={this.onSelectionChange}
/>
</Grid>
<Grid item xs={12}>
<TextField
name="essay2"
label="Essay 2"
multiline
rows={3}
fullWidth
onMouseUp={this.onSelectionChange}
/>
</Grid>
</Grid>
</Box>
);
}
}
答案 1 :(得分:1)
您需要为要访问的每个dom节点创建一个引用。
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
selStart: undefined,
selEnd: undefined,
selValue: undefined
};
this.onSaveSelectionClicked = this.onSaveSelectionClicked.bind(this);
// Don't forget to attach refs to dom nodes accordingly!
this.firstTextFieldRef = createRef();
this.secondTextFieldRef = createRef();
}
// Rest of your component...
}
然后,您可以收听每个textArea的焦点事件,以了解上一次被选中的文本(因此包含所选文本),或者可以依靠不能同时在两个文本区域中选择文本这一事实(并非完全正确)。
焦点选项是更干净的IMO:
// Using function composition to avoid logic duplication
handleTextFieldFocus = ref => () => {
this.setState({ lastSelectedField: ref })
}
// Attach to your first text area
handleFirstFieldFocus = handleTextFieldFocus(this.firstTextFieldRef)
// Attach to your second text area
handleSecondFieldFocus = handleTextFieldFocus(this.secondTextFieldRef)
onSaveSelectionClicked() {
// We are getting the values from the last focused input
const {
selectionStart,
selectionEnd,
value
} = this.state.lastSelectedField.current;
this.setState({
selStart: selectionStart,
selEnd: selectionEnd,
selValue: value.substring(selectionStart, selectionEnd)
});
}
第二个选项意味着在设置状态之前检查每个ref的值:
onSaveSelectionClicked() {
let {
selectionStart,
selectionEnd,
value
} = this.firstTextFieldRef.current;
// If there is no selected text in the first text field
// we will assume that there must be on the second text area
if (!firstSelectionStart && !firstSelectionEnd) {
selectionStart = this.secondTextFieldRef.current.selectionStart
selectionEnd = this.secondTextFieldRef.current.selectionEnd
value = this.secondTextFieldRef.current.value
}
this.setState({
selStart: selectionStart,
selEnd: selectionEnd,
selValue: value.substring(selectionStart, selectionEnd)
});
}