从Material UI的TextField获取选择开始,结束和选择值

时间:2020-04-11 12:33:17

标签: reactjs material-ui

我需要从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>
    );
  }
}

哪个给我以下内容

enter image description here

问题是,这似乎不适用于多个TextField。引用的current属性将始终引用“论文2”文本字段。

有没有更好的方法来解决这个问题?

以下是上述代码的指向codesandbox的链接

2 个答案:

答案 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)
  });
}