En javascript simple, j'ai le DIV
<div class="movie" id="my_movie">
et le code javascript suivant
var myMovie = document.getElementById('my_movie');
myMovie.addEventListener('nv-enter', function (event) {
console.log('change scope');
});
Maintenant, j'ai un composant React, à l'intérieur de ce composant, dans la méthode de rendu, je retourne mon div. Comment puis-je ajouter un écouteur d'événement pour mon événement personnalisé? (J'utilise cette bibliothèque pour les applications TV - 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;
Mise à jour n ° 1:
J'ai appliqué toutes les idées fournies dans les réponses. J'ai mis la bibliothèque de navigation en mode débogage et je suis capable de naviguer sur mes éléments de menu uniquement en fonction du clavier (comme vous pouvez le voir sur la capture d'écran, j'ai pu naviguer vers Films 4) mais lorsque je concentre un élément dans le menu ou appuyez sur Entrée, je ne vois rien dans la 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;
J'ai laissé quelques lignes commentées car dans les deux cas, je ne parviens pas à enregistrer les lignes de la console.
Mise à jour n ° 2: Cette bibliothèque de navigation ne fonctionne pas bien avec React avec ses balises Html d'origine, j'ai donc dû définir les options et renommer les balises pour utiliser aria- * afin que cela n'impacte pas 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)
) et d'utiliser des initialiseurs de propriété ES7 avec des fonctions fléchées (handleNVEnter = enter => {}
) car les fonctions flèches grasses sont toujours liées. Si vous pouvez utiliser la syntaxe ES7, allez-y.aria-*
endata-*
parce que les attributs ARIA proviennent d'un ensemble standard, vous ne pouvez pas créer les vôtres. Les attributs de données peuvent être définis plus arbitrairement sur ce que vous voulez.Réponses:
Si vous avez besoin de gérer des événements DOM qui ne sont pas déjà fournis par React, vous devez ajouter des écouteurs DOM une fois le composant monté:
Mise à jour: Entre React 13, 14 et 15, des modifications ont été apportées à l'API qui affectent ma réponse. Vous trouverez ci-dessous la dernière façon d'utiliser React 15 et ES7. Consultez l' historique des réponses pour les anciennes 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> ); } }
Exemple sur Codepen.io
la source
findDOMNode
. Dans votre cas, celavar elem = this.refs.nv;
suffit.edited Aug 19 at 6:19
texte sous l'article, qui vous amène à l' historique des révisions .nv.dispatchEvent()
si vous en avez besoin.Vous pouvez utiliser les méthodes componentDidMount et 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;
la source
Tout d'abord, les événements personnalisés ne fonctionnent pas bien avec les composants React de manière native. Vous ne pouvez donc pas simplement le dire
<div onMyCustomEvent={something}>
dans la fonction de rendu et vous devez penser au problème.Deuxièmement, après avoir jeté un coup d'œil à la documentation de la bibliothèque que vous utilisez, l'événement est en fait déclenché
document.body
, donc même s'il fonctionnait, votre gestionnaire d'événements ne se déclencherait jamais.Au lieu de cela,
componentDidMount
quelque part dans votre application, vous pouvez écouter nv-enter en ajoutantdocument.body.addEventListener('nv-enter', function (event) { // logic });
Ensuite, à l'intérieur de la fonction de rappel, appuyez sur une fonction qui change l'état du composant, ou tout ce que vous voulez faire.
la source