web-dev-qa-db-ja.com

Reactおよびblurイベント

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:テーブルのフォーカスが失われたことを示すイベントのみを表示するように、バブルになっている不要なイベントを除外して破棄するにはどうすればよいですか?

23
Peter Perot

問題は、テーブル自体が入力ではないため、テーブルに実際にフォーカスの概念がないことです。

OnBlurが含まれる入力で起動すると、RECEIVEDフォーカス(またはrelatedTarget)を持つ要素に設定する必要があるonBlurイベントのnullを確認します。次に、その新しくフォーカスされた要素からparentNodesを上方向にたどる関数を使用し、イベントの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" />

参照:

更新:

ReactDOM.findDOMNodeの使用を削除

25
TheZanke

Withoutカスタム関数とInternet Explorer互換_node.contains_ および _document.activeElement_ は、Internet Explorer 5以降でサポートされています。

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

  • Node.contains()メソッドは、ノードが特定のノードの子孫であるかどうかを示すブール値を返します。
  • Document.activeElementは、現在フォーカスされている要素、つまりユーザーが入力した場合にキーストロークイベントを取得する要素を返します。
5

うまくいけば、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を離れたときに基づいて、保存アクションをトリガーしようとしていました。

4
Chris Paul