反应和模糊事件

时间:2016-06-24 17:35:30

标签: javascript html html5 reactjs dom-events

我对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>;

我希望blur事件仅在焦点超出表时触发。相反,事件在失去焦点时会激活表格的每个子元素

根据文档,React让焦点事件冒出来。

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

4 个答案:

答案 0 :(得分:23)

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

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

&#13;
&#13;
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')
);
&#13;
table {
  padding: 10px;
  border: 1px solid red;
}
&#13;
<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" />
&#13;
&#13;
&#13;

参考文献:

<强>更新:

删除了对ReactDOM.findDOMNode

的使用

答案 1 :(得分:4)

没有自定义功能和兼容Internet Explorer ,因为自Internet Explorer 5以来支持node.containsdocument.activeElement,所以可以:

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

  
      
  • Node.contains()方法返回一个布尔值,指示节点是否是给定节点的后代。
  •   
  • Document.activeElement返回当前关注的元素,即用户键入任何键击事件时将获取击键事件的元素。
  •   

答案 2 :(得分:2)

只是希望综合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>
    )
  }
}

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

答案 3 :(得分:0)

一种快速的方法是:

  1. onBluronFocus事件连接到您的父元素
  2. 发生模糊时,使用setTimeout启动计时器
  3. 清除焦点发生时的超时。

它看起来像这样:

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>
    )
  }
)

之所以可行,是因为所有子模糊都将冒泡到父级,然后焦点事件将取消它们,除非焦点已移到父级之外。

对于J.RenéeBeach及其出色的Medium article表示敬意,以了解此解决方案的基础。