简体   繁体   English

防止 material-ui 弹出元素的自动聚焦

[英]Prevent auto focus of a material-ui popover element

I am attempting to create a search match list that updates as the user types in their query.我正在尝试创建一个搜索匹配列表,该列表会随着用户在查询中键入而更新。 However, I can't figure out how to maintain focus on the input element.但是,我无法弄清楚如何保持对输入元素的关注。 The pop-up always gets focussed.弹出窗口总是聚焦。 I have tried programmatically setting the focus using refs but I cannot give a stateless function component (I'm assuming this is my TextField input) a ref.我曾尝试使用 refs 以编程方式设置焦点,但我无法为无状态函数组件(我假设这是我的 TextField 输入)提供 ref。

Here is a gif of the behavior.这是行为的 gif。 https://imgur.com/a/JVskedr https://imgur.com/a/JVskedr

Notice how the popup steals focus and prevents the user from typing further.请注意弹出窗口如何窃取焦点并阻止用户进一步输入。

<TextField
              id='contact'
              label='Contact Name'
              className={classes.textField}
              margin='normal'
              ref={this.nameInput}
              onChange={this.handleContactSearch.bind(this)}
              value={this.state.contactSearch}
            />
            <Popover
              open={Boolean(anchorEl)}
              anchorEl={anchorEl}
              onClick={this.handlePopoverClose}
              anchorOrigin={{
                vertical: 'bottom',
                horizontal: 'center'
              }}
              transformOrigin={{
                vertical: 'top',
                horizontal: 'center'
              }}
              autoFocus={false}
            >
              <List>{this.createContactList()}</List>
            </Popover>

These are the related functions:这些是相关的功能:

  handleContactSearch(event) {
    this.handlePopoverClick(event);
    this.setState({ contactSearch: handleText(event) });
    this.props.filterContacts(
      event.target.value,
      this.props.accountInfo.AccountName
    );
  }
  handlePopoverClick = event => {
    this.setState({
      anchorEl: event.currentTarget
    });
  };

  handlePopoverClose = () => {
    this.setState({
      anchorEl: null
    });
  };

How can I make the TextField element maintain focus so a user can type their query without interruption?如何使 TextField 元素保持焦点,以便用户可以不间断地输入查询?

Sandbox: https://codesandbox.io/s/mjqoj9lxkj沙盒: https : //codesandbox.io/s/mjqoj9lxkj

Pass 'disableAutoFocus', 'disableEnforceFocus' props to your popover.将“disableAutoFocus”、“disableEnforceFocus”道具传递给您的弹出框。 It worked for me!它对我有用!

<Popover
 open={Boolean(anchorEl)}

 // pass these props to the popover component
 disableAutoFocus={true}
 disableEnforceFocus={true}
 >

https://material-ui.com/api/modal/ https://material-ui.com/api/modal/

The reason why this is happening is that you are calling this.showPopover(event) every time the onChange={this.handleContactSearch.bind(this)} event is fired in your <TextField> .发生这种情况的原因是每次在您的<TextField>触发onChange={this.handleContactSearch.bind(this)}事件时,您都会调用this.showPopover(event)

In order to fix this, you'll need to find a way to call this.showPopover(event) only once.为了解决这个问题,您需要找到一种方法,只调用一次this.showPopover(event)

I was able to make it work using a combination of autoFocus={true} and the onFocus={this.showPopover} event on the <TextField/> .我能够使用<TextField/>上的autoFocus={true}onFocus={this.showPopover}事件的组合使其工作。 The only issue with this is that the popover will show up empty when you first open the modal.唯一的问题是当您第一次打开模态时,弹出窗口将显示为空。 I used a ref on the textfield and a conditional to set the opacity of the popover so it only shows once there's a value in the textfield.我在文本字段上使用了ref并使用了条件来设置弹出框的不透明度,因此它仅在文本字段中有值时才显示。

Maybe not the ultimate solution, but it works and should at least send you in the right direction.也许不是最终的解决方案,但它有效,至少应该让你朝着正确的方向前进。

<div className={classes.paper}>
    <TextField
        id="contact123"
        label="Contact Name"
        className={classes.textField}
        margin="normal"
        onChange={this.handleContactSearch.bind(this)}
        value={this.state.contactSearch}
        autoFocus={true}
        onFocus={this.showPopover}
        inputRef={input => (this.tf = input)}
    />
    <Popover
        open={Boolean(anchorEl)}
        anchorEl={document.getElementById("contact123")}
        onClick={this.closePopover}
        anchorOrigin={{
            vertical: "bottom",
            horizontal: "center"
        }}
        transformOrigin={{
            vertical: "top",
            horizontal: "center"
        }}
        style={{ opacity: this.tf && !this.tf.value.length ? 0 : 1 }}
    >
        <List>{this.state.contactSearch}</List>
    </Popover>
    <div>
        <Button color="primary" className={classes.saveButton}>
            Save
        </Button>
    </div>
</div>

Sandbox: Working Demo沙盒:工作演示

An alternative to this approach is to use Popper , ClickAwayListener and Backdrop components.这种方法的替代方法是使用PopperClickAwayListenerBackdrop组件。 Using Popper allows you to preserve focus on the input field and keep typing.使用Popper可以让您专注于输入字段并继续输入。 The solution would look roughly like:解决方案大致如下:

class Foo extends React.Component {
  inputRef = React.createRef(),

  render() {
    const { open, searchValue } = this.state

    <RootRef rootRef={this.inputRef}>
      <div className={classes.container}>
        // You may be able to use TextField as well
        <FormControl
          onKeyDown={//set open = false}
          onClick={// set open = true (e.g. only when searchValue !== '' }
        >
          <InputBase
            value={searchValue}
            onChange={this.handleSearchValueChange}
            inputRef={this.inputRef}
          />
        </FormControl>
        <Popper anchorEl={this.inputRef.current} open={open} >
          <ClickAwayListener onClick={//set open = false} onClickAway={//set open = false}>
            Popover content
          </ClickAwayListener>
        </Popper>
      </div>
    </RootRef>
  }
}

Not a working example, but shows how to solve the problem of being able to type in an input while having popover/popper opened.不是一个工作示例,但展示了如何解决在打开 popover/popper 时能够输入输入的问题。

You can add onKeyDown property to the popover that will close it every time the user will type, and onKeyUp property to the search input which pops up the popover again.您可以将 onKeyDown 属性添加到每次用户键入时将关闭它的弹出窗口,并将 onKeyUp 属性添加到再次弹出弹出窗口的搜索输入。 not the best solution but it's worked for me.不是最好的解决方案,但它对我有用。

<InputBase
              autoFocus={true}
              value={searchText}
              onChange={(e) => handleSearch(e)}
              onKeyUp={e => setAnchorEl(e.currentTarget)}
              placeholder="Search…"
              classes={{
                root: classes.inputRoot,
                input: classes.inputInput,
              }}
              inputProps={{ "aria-label": "search" }}
            />
            {searchResult && (
              <Popover
              disableAutoFocus 
              className={classes.pop}
              onKeyDown={handleClose}
                id={id}
                open={open}
                anchorEl={anchorEl}
                onClose={handleClose}
                anchorOrigin={{
                  vertical: "bottom",
                  horizontal: "center",
                }}
                transformOrigin={{
                  vertical: "top",
                  horizontal: "center",
                }}
              >
                {searchResult.map((song, i) => {
                  return (
                      <Link to={`/Songs/${song.unique_id}?Artist=${song.artist_id}`}>
                    <ListItem>
                    <IconButton variant="h6" >
                      <PlayCircleFilledRounded/>
                    </IconButton>
                      {song.title}
                      </ListItem>
                      </Link>
                  );
                })}
              </Popover>
            )}
          </div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM