ReactJS - 向组件添加自定义事件侦听器 [英] ReactJS - Add custom event listener to component

查看:52
本文介绍了ReactJS - 向组件添加自定义事件侦听器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在普通的旧 HTML 中,我有 DIV

和下面的javascript代码

var myMovie = document.getElementById('my_movie');myMovie.addEventListener('nv-enter', function (event) {console.log('更改范围');});

现在我有一个 React 组件,在这个组件中,在 render 方法中,我正在返回我的 div.如何为我的自定义事件添加事件侦听器?(我将此库用于电视应用程序 -

我应用了答案中提供的所有想法.我将导航库设置为调试模式,并且我只能基于键盘在我的菜单项上导航(如您在屏幕截图中看到的那样,我能够导航到电影 4)但是当我聚焦菜单中的一个项目时或按 Enter,我在控制台中没有看到任何内容.

import React, { Component } from 'react';从 'react-dom' 导入 ReactDOM;类 MenuItem 扩展组件 {构造函数(道具){超级(道具);//预先绑定你的事件处理程序,或者在 ES7/TS 中将其定义为一个粗箭头this.handleNVFocus = this.handleNVFocus.bind(this);this.handleNVEnter = this.handleNVEnter.bind(this);this.handleNVRight = this.handleNVRight.bind(this);}handleNVFocus = 事件 =>{console.log('重点:' + this.props.menuItem.caption.toUpperCase());}handleNVEnter = 事件 =>{console.log('输入:' + this.props.menuItem.caption.toUpperCase());}handleNVRight = 事件 =>{console.log('右:' + this.props.menuItem.caption.toUpperCase());}componentDidMount() {ReactDOM.findDOMNode(this).addEventListener('nv-focus', this.handleNVFocus);ReactDOM.findDOMNode(this).addEventListener('nv-enter', this.handleNVEnter);ReactDOM.findDOMNode(this).addEventListener('nv-right', this.handleNVEnter);//this.refs.nv.addEventListener('nv-focus', this.handleNVFocus);//this.refs.nv.addEventListener('nv-enter', this.handleNVEnter);//this.refs.nv.addEventListener('nv-right', this.handleNVEnter);}componentWillUnmount() {ReactDOM.findDOMNode(this).removeEventListener('nv-focus', this.handleNVFocus);ReactDOM.findDOMNode(this).removeEventListener('nv-enter', this.handleNVEnter);ReactDOM.findDOMNode(this).removeEventListener('nv-right', this.handleNVRight);//this.refs.nv.removeEventListener('nv-focus', this.handleNVFocus);//this.refs.nv.removeEventListener('nv-enter', this.handleNVEnter);//this.refs.nv.removeEventListener('nv-right', this.handleNVEnter);}使成为() {var attrs = this.props.index === 0 ?{aria-nv-el-current":真}:{};返回 (<div ref=nv";aria-nv-el {...attrs} className=menu_item nv-default"><div className="indicator selected"></div><div className="类别"><span className="title">{this.props.menuItem.caption.toUpperCase()}</span>

)}}导出默认菜单项;

我留下了一些注释行,因为在这两种情况下我都无法记录控制台行.

更新 #2:这个导航库不能很好地与带有原始 Html 标签的 React 配合使用,所以我必须设置选项并重命名标签以使用 aria-* 以免影响 React.

navigation.setOption('prefix','aria-nv-el');navigation.setOption('attrScope','aria-nv-scope');navigation.setOption('attrScopeFOV','aria-nv-scope-fov');navigation.setOption('attrScopeCurrent','aria-nv-scope-current');navigation.setOption('attrElement','aria-nv-el');navigation.setOption('attrElementFOV','aria-nv-el-fov');navigation.setOption('attrElementCurrent','aria-nv-el-current');

解决方案

如果您需要处理尚未由 React 提供的 DOM 事件 您必须在安装组件后添加 DOM 侦听器:

更新:在 React 13、14 和 15 之间,对影响我的回答的 API 进行了更改.下面是使用 React 15 和 ES7 的最新方法.有关旧版本,请参阅回答历史.

class MovieItem extends React.Component {componentDidMount() {//挂载组件后,将 DOM 侦听器添加到nv";元素.//(nv"元素是在渲染函数中分配的.)this.nv.addEventListener(nv-enter", this.handleNvEnter);}componentWillUnmount() {//确保在卸载组件时移除 DOM 侦听器.this.nv.removeEventListener(nv-enter", this.handleNvEnter);}//为处理程序使用类箭头函数 (ES7).在 ES6 中你可以 bind()//构造函数中的处理程序.handleNvEnter = (事件) =>{console.log("Nv Enter:", 事件);}使成为() {//这里我们渲染一个 

并切换aria-nv-el-current";属性//使用属性扩展运算符.这样只有一个

//曾经被挂载,我们不必担心添加/删除//每次当前索引更改时都会有一个 DOM 监听器.属性//是传播"到<div>在渲染函数中:{...attrs}const attrs = this.props.index === 0 ?{aria-nv-el-current":真}:{};//最后,使用ref"渲染 div;分配挂载的回调//elem 到类属性nv";用于添加 DOM 侦听器.返回 (<div ref={elem =>this.nv = elem} aria-nv-el {...attrs} className=menu_item nv-default">...

);}}

Codepen.io 上的示例

In plain old HTML I have the DIV

<div class="movie" id="my_movie">

and the following javascript code

var myMovie = document.getElementById('my_movie');
myMovie.addEventListener('nv-enter', function (event) {
     console.log('change scope');
});

Now I have a React Component, inside this component, in the render method, I am returning my div. How can I add an event listener for my custom event? (I am using this library for TV apps - navigation )

import React, { Component } from 'react';

class MovieItem extends Component {

  render() {

    if(this.props.index === 0) {
      return (
        <div aria-nv-el aria-nv-el-current className="menu_item nv-default">
            <div className="indicator selected"></div>
            <div className="category">
                <span className="title">{this.props.movieItem.caption.toUpperCase()}</span>
            </div>
        </div>
      );
    }
    else {
      return (
        <div aria-nv-el className="menu_item nv-default">
            <div className="indicator selected"></div>
            <div className="category">
                <span className="title">{this.props.movieItem.caption.toUpperCase()}</span>
            </div>
        </div>
      );
    }
  }

}

export default MovieItem;

Update #1:

I applied all the ideas provided in the answers. I set the navigation library to debug mode and I am able to navigate on my menu items only based on the keyboard (as you can see in the screenshot I was able to navigate to Movies 4) but when I focus an item in the menu or press enter, I dont see anything in the console.

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class MenuItem extends Component {

  constructor(props) {
    super(props);
    // Pre-bind your event handler, or define it as a fat arrow in ES7/TS
    this.handleNVFocus = this.handleNVFocus.bind(this);
    this.handleNVEnter = this.handleNVEnter.bind(this);
    this.handleNVRight = this.handleNVRight.bind(this);
  }

  handleNVFocus = event => {
      console.log('Focused: ' + this.props.menuItem.caption.toUpperCase());
  }

  handleNVEnter = event => {
      console.log('Enter: ' + this.props.menuItem.caption.toUpperCase());
  }

  handleNVRight = event => {
      console.log('Right: ' + this.props.menuItem.caption.toUpperCase());
  }

  componentDidMount() {
    ReactDOM.findDOMNode(this).addEventListener('nv-focus', this.handleNVFocus);
    ReactDOM.findDOMNode(this).addEventListener('nv-enter', this.handleNVEnter);
    ReactDOM.findDOMNode(this).addEventListener('nv-right', this.handleNVEnter);
    //this.refs.nv.addEventListener('nv-focus', this.handleNVFocus);
    //this.refs.nv.addEventListener('nv-enter', this.handleNVEnter);
    //this.refs.nv.addEventListener('nv-right', this.handleNVEnter);
  }

  componentWillUnmount() {
    ReactDOM.findDOMNode(this).removeEventListener('nv-focus', this.handleNVFocus);
    ReactDOM.findDOMNode(this).removeEventListener('nv-enter', this.handleNVEnter);
    ReactDOM.findDOMNode(this).removeEventListener('nv-right', this.handleNVRight);
    //this.refs.nv.removeEventListener('nv-focus', this.handleNVFocus);
    //this.refs.nv.removeEventListener('nv-enter', this.handleNVEnter);
    //this.refs.nv.removeEventListener('nv-right', this.handleNVEnter);
  }

  render() {
    var attrs = this.props.index === 0 ? {"aria-nv-el-current": true} : {};
    return (
      <div ref="nv" aria-nv-el {...attrs} className="menu_item nv-default">
          <div className="indicator selected"></div>
          <div className="category">
              <span className="title">{this.props.menuItem.caption.toUpperCase()}</span>
          </div>
      </div>
    )
  }

}

export default MenuItem;

I left some lines commented because in both cases I am not able to get the console lines to be logged.

Update #2: This navigation library does not work well with React with its original Html Tags, so I had to set the options and rename the tags to use aria-* so it would not impact React.

navigation.setOption('prefix','aria-nv-el');
navigation.setOption('attrScope','aria-nv-scope');
navigation.setOption('attrScopeFOV','aria-nv-scope-fov');
navigation.setOption('attrScopeCurrent','aria-nv-scope-current');
navigation.setOption('attrElement','aria-nv-el');
navigation.setOption('attrElementFOV','aria-nv-el-fov');
navigation.setOption('attrElementCurrent','aria-nv-el-current');

解决方案

If you need to handle DOM events not already provided by React you have to add DOM listeners after the component is mounted:

Update: Between React 13, 14, and 15 changes were made to the API that affect my answer. Below is the latest way using React 15 and ES7. See answer history for older versions.

class MovieItem extends React.Component {

  componentDidMount() {
    // When the component is mounted, add your DOM listener to the "nv" elem.
    // (The "nv" elem is assigned in the render function.)
    this.nv.addEventListener("nv-enter", this.handleNvEnter);
  }

  componentWillUnmount() {
    // Make sure to remove the DOM listener when the component is unmounted.
    this.nv.removeEventListener("nv-enter", this.handleNvEnter);
  }

  // Use a class arrow function (ES7) for the handler. In ES6 you could bind()
  // a handler in the constructor.
  handleNvEnter = (event) => {
    console.log("Nv Enter:", event);
  }

  render() {
    // Here we render a single <div> and toggle the "aria-nv-el-current" attribute
    // using the attribute spread operator. This way only a single <div>
    // is ever mounted and we don't have to worry about adding/removing
    // a DOM listener every time the current index changes. The attrs 
    // are "spread" onto the <div> in the render function: {...attrs}
    const attrs = this.props.index === 0 ? {"aria-nv-el-current": true} : {};

    // Finally, render the div using a "ref" callback which assigns the mounted 
    // elem to a class property "nv" used to add the DOM listener to.
    return (
      <div ref={elem => this.nv = elem} aria-nv-el {...attrs} className="menu_item nv-default">
        ...
      </div>
    );
  }

}

Example on Codepen.io

这篇关于ReactJS - 向组件添加自定义事件侦听器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆