В простом старом javascript у меня есть DIV
<div class="movie" id="my_movie">
и следующий код javascript
var myMovie = document.getElementById('my_movie');
myMovie.addEventListener('nv-enter', function (event) {
console.log('change scope');
});
Теперь у меня есть компонент React, внутри этого компонента, в методе рендеринга, я возвращаю свой div. Как я могу добавить прослушиватель событий для моего настраиваемого события? (Я использую эту библиотеку для ТВ приложений - навигация )
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;
Обновление №1:
Я применил все идеи, изложенные в ответах. Я установил библиотеку навигации в режим отладки, и я могу перемещаться по элементам меню только с помощью клавиатуры (как вы можете видеть на снимке экрана, я смог перейти к Фильмам 4), но когда я фокусирую элемент в меню или жму ввод, в консоли ничего не вижу.
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;
Я оставил некоторые строки прокомментированными, потому что в обоих случаях я не могу зарегистрировать строки консоли.
Обновление №2: эта навигационная библиотека плохо работает с React с его исходными тегами Html, поэтому мне пришлось установить параметры и переименовать теги, чтобы использовать 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');
this.handleNVEnter = this.handleNVEnter.bind(this)
) и использовать инициализаторы свойств ES7 с функциями стрелок (handleNVEnter = enter => {}
), потому что функции жирных стрелок всегда связаны. Если вы можете использовать синтаксис ES7, просто сделайте это.aria-*
на,data-*
потому что атрибуты ARIA взяты из стандартного набора, вы не можете создавать свои собственные. Атрибуты данных могут быть более произвольно установлены так, как вы хотите.Ответы:
Если вам нужно обрабатывать события DOM, которые еще не предоставлены React, вам необходимо добавить прослушиватели DOM после монтирования компонента:
Обновление: между React 13, 14 и 15 в API были внесены изменения, которые повлияли на мой ответ. Ниже представлен последний способ использования React 15 и ES7. См. Историю ответов для более старых версий.
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> ); } }
Пример на Codepen.io
источник
findDOMNode
. В твоем случае этогоvar elem = this.refs.nv;
достаточно.edited Aug 19 at 6:19
текст под сообщением, чтобы перейти к истории изменений .nv.dispatchEvent()
если вам нужно.Вы можете использовать методы componentDidMount и componentWillUnmount :
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; class MovieItem extends Component { _handleNVEvent = event => { ... }; componentDidMount() { ReactDOM.findDOMNode(this).addEventListener('nv-event', this._handleNVEvent); } componentWillUnmount() { ReactDOM.findDOMNode(this).removeEventListener('nv-event', this._handleNVEvent); } [...] } export default MovieItem;
источник
Во-первых, пользовательские события изначально не работают с компонентами React. Таким образом, вы не можете просто сказать
<div onMyCustomEvent={something}>
в функции рендеринга и должны обдумать проблему.Во-вторых, после просмотра документации по используемой вами библиотеке событие фактически запускается
document.body
, поэтому, даже если оно сработает, ваш обработчик событий никогда не сработает.Вместо этого внутри
componentDidMount
где-то в вашем приложении вы можете прослушивать nv-enter, добавивdocument.body.addEventListener('nv-enter', function (event) { // logic });
Затем внутри функции обратного вызова нажмите функцию, которая изменяет состояние компонента, или все, что вы хотите сделать.
источник