Javascript 反应和模糊事件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38019140/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 20:59:13  来源:igfitidea点击:

React and blur event

javascripthtmlreactjsdom-events

提问by Peter Perot

I have a simple issue with React and event handling. My component looks like this (basically a table):

我在 React 和事件处理方面有一个简单的问题。我的组件看起来像这样(基本上是一个表格):

const MyList = ({ items, onBlur }) =>
<table onBlur={onBlur}}>
    <thead>
    <tr>
        <th>ID</th>
        <th>Title</th>
        <th>Publisher</th>
        <th>Year</th>
        <th>Author</th>
        <th>System</th>
        <th/>
    </tr>
    </thead>
    <tbody>
    {items.map(item => <MyListRow key={item.Id} item={item}/>)}
    </tbody>
</table>;

I want the blurevent to fire only if the focus goes out of the table. Instead the event fires on each child element of the tablewhen it loses focus.

我希望只有当焦点离开表格时才blur触发事件。相反,当失去焦点时,该事件会在表的每个子元素上触发

According to the docs React lets focus events bubble up.

根据文档 React 让焦点事件冒泡。

The question is: How can I get my onBlurmethod fire only when the focus gets out of the table? IOW: How can I filter out and discard the unwanted events bubbling up so that I reveal only the events which indicate a lost of focus for the table?

问题是:onBlur只有当焦点离开表格时,我才能触发我的方法吗?IOW:如何过滤和丢弃冒泡的不需要的事件,以便仅显示表明表失去焦点的事件?

回答by TheZanke

The problem is that a table doesn't actually have a concept of focus since it's not an input itself.

问题是表格实际上没有焦点的概念,因为它本身不是输入。

When the onBlur fires on the contained inputs we will check the relatedTargetof the onBlurevent which should be set to the element that has RECEIVED focus (or null). We then use a function that will traverse upwards through parentNodes from that newly focused element and ensure that our event's currentTarget(the table) is not an ancestor of the newly focused element. If the condition passes it is assumed that the table no longer has any focus.

当 onBlur 在包含的输入上触发时,我们将检查应设置为具有 RECEIVED 焦点(或)的元素relatedTargetonBlur事件的null。然后我们使用一个函数,该函数parentNode将从新聚焦的元素向上遍历s,并确保我们的事件currentTarget(表)不是新聚焦元素的祖先。如果条件通过,则假定该表不再具有任何焦点。

const focusInCurrentTarget = ({ relatedTarget, currentTarget }) => {
  if (relatedTarget === null) return false;
  
  var node = relatedTarget.parentNode;
        
  while (node !== null) {
    if (node === currentTarget) return true;
    node = node.parentNode;
  }

  return false;
}

const onBlur = (e) => {
  if (!focusInCurrentTarget(e)) {
    console.log('table blurred');
  }
}

const MyList = ({ items, onBlur }) => (
  <table onBlur={onBlur}>
    <thead>
      <tr>
        <th>ID</th>
        <th>Title</th>
        <th>Publisher</th>
        <th>Year</th>
        <th>Author</th>
        <th>System</th>
        <th/>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>1</td>
        <td>
          <input type="text" />
        </td>
        <td>
          <input type="text" />
        </td>
        <td>
          <input type="text" />
        </td>
        <td>
          <input type="text" />
        </td>
        <td>
          <input type="text" />
        </td>
      </tr>
    </tbody>
  </table>
);
    
ReactDOM.render(
  <MyList onBlur={onBlur} />,
  document.getElementById('root')
);
table {
  padding: 10px;
  border: 1px solid red;
}
<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>
<div id="root"></div>
<br />
<input type="text" />

References:

参考:

UPDATED:

更新:

Removed use of ReactDOM.findDOMNode

删除了 ReactDOM.findDOMNode 的使用

回答by David Riccitelli

Withoutcustom functions and Internet Explorer compatible, since node.containsand document.activeElementare supported since Internet Explorer 5, this works:

没有自定义功能和Internet Explorer 兼容,因为node.contains并且document.activeElement自 Internet Explorer 5起支持,这有效:

const onBlur = (e) => { if ( !e.currentTarget.contains( document.activeElement ) ) { console.log('table blurred'); } }

const onBlur = (e) => { if ( !e.currentTarget.contains( document.activeElement ) ) { console.log('table blurred'); } }

  • The Node.contains() method returns a Boolean value indicating whether a node is a descendant of a given node or not.
  • Document.activeElement returns the currently focused element, that is, the element that will get keystroke events if the user types any.
  • Node.contains() 方法返回一个布尔值,指示节点是否是给定节点的后代。
  • Document.activeElement 返回当前聚焦的元素,即,如果用户键入任何内容,将获得击键事件的元素。

回答by Chris Paul

Just to hopefully synthesise David Riccitelli's helpful pointer, and wintondeshong's later insight, this worked for me:

只是为了希望综合 David Riccitelli 的有用指针和 wintondeshong 后来的见解,这对我有用:

class ActionRow extends Component {

  onBlur = (e) => {
    if ( !e.currentTarget.contains( e.relatedTarget ) ) {
      console.log('blur event');
    }
  }

  render() {
    return (
      <div onBlur={this.onBlur}>
        ..
      </div>
    )
  }
}

I was trying to trigger a save action based on when focus left a div full of form fields.

我试图根据焦点何时离开充满表单字段的 div 来触发保存操作。

回答by Kaiden

A quick way to do this is to:

一个快速的方法是:

  1. Wire up an onBlurand onFocusevent to your parent element
  2. Start a timer with setTimeoutwhen blur happens
  3. Clear the timeout when the focus happens.
  1. 将一个onBluronFocus事件连接到您的父元素
  2. setTimeout当模糊发生时启动计时器
  3. 焦点发生时清除超时。

It would look something like this:

它看起来像这样:

class MyList extends Component {
  onBlur() {
    this.blurTimeoutHandle = setTimeout(this.props.onBlur)
  }
  onFocus() {
    clearTimeout(this.blurTimeoutHandle)
  }

  render() {
    return (
      <table onBlur={this.onBlur} onFocus={this.onFocus}>
      ...
      </table>
    )
  }
)

This works because all the child blurs will bubble up to the parent and then the focus events will cancel them unless focus has moved outside the parent.

这是有效的,因为所有子模糊都会冒泡到父对象,然后焦点事件将取消它们,除非焦点移到父对象之外。

Kudos to J. Renée Beach and her great Medium articlefor the basics of this solution.

感谢J. Renée Beach 和她关于此解决方案基础知识的优秀Medium 文章