javascript - onClick funguje, ale onDoubleClick je na React komponente ignorovaný
Tvoriť hru Minesweeper s Reactom a chcem vykonať inú akciu, keď je bunka kliknutá raz alebo dvakrát. Momentálne funkcia onDoubleClick nikdy nespustí, zobrazí sa výstraha z onClick. Ak odstránim obsluhu onClick, onDoubleClick funguje. Prečo obe udalosti nefungujú? Je možné mať obe udalosti na jednom elemente?
/** @jsx React.DOM */
var Mine = React.createClass({
render: function(){
return (
<div className="mineBox" id={this.props.id} onDoubleClick={this.props.onDoubleClick} onClick={this.props.onClick}></div>
)
}
});
var MineRow = React.createClass({
render: function(){
var width = this.props.width,
row = [];
for (var i = 0; i < width; i++){
row.push(<Mine id={String(this.props.row + i)} boxClass={this.props.boxClass} onDoubleClick={this.props.onDoubleClick} onClick={this.props.onClick}/>)
}
return (
<div>{row}</div>
)
}
})
var MineSweeper = React.createClass({
handleDoubleClick: function(){
alert('Double Clicked');
},
handleClick: function(){
alert('Single Clicked');
},
render: function(){
var height = this.props.height,
table = [];
for (var i = 0; i < height; i++){
table.push(<MineRow width={this.props.width} row={String.fromCharCode(97 + i)} onDoubleClick={this.handleDoubleClick} onClick={this.handleClick}/>)
}
return (
<div>{table}</div>
)
}
})
var bombs = ['a0', 'b1', 'c2'];
React.renderComponent(<MineSweeper height={5} width={5} bombs={bombs}/>, document.getElementById('content'));
Odpoveď č. 1
Toto nie je obmedzenie Reactu, je to obmedzenie udalostí click a dblclick DOMu. Ako navrhuje dokumentácia kliknutí Quirksmode:
Neregistrujte udalosti kliknutia a dvojitého kliknutia na rovnakom prvku: je nemožné odlíšiť jednoclickové udalosti od udalostí kliknutia, ktoré vedú k udalosti dvojitého kliknutia.
Pre aktuálnejšiu dokumentáciu uvádza špecifikácia W3C o udalosti dblclick:
Používateľský agent musí vyslať túto udalosť, keď je primárne tlačidlo ukazovacieho zariadenia dvakrát kliknuté na prvku.
Udalosť dvojitého kliknutia sa nevyhnutne udeje po dvoch udalostiach kliknutia.
Upraviť:
Ešte jednou odporúčanou čítanou je jQuery dblclick handler:
Nie je vhodné pripájať obsluhovateľov udalostí k udalostiam click aj dblclick pre ten istý prvok. Poradie spúšťaných udalostí sa líši v závislosti od prehliadača, pričom niektoré prijímajú dve udalosti click pred dblclick a iné len jednu. Citlivosť na dvojité kliknutie (maximálny čas medzi kliknutiami, ktorý sa rozpozná ako dvojité kliknutie) sa môže líšiť podľa operačného systému a prehliadača a často je nastaviteľná používateľom.
Odpoveď č. 2
Namiesto používania ondoubleclick môžete použiť event.detail na získanie aktuálneho počtu kliknutí. Je to počet, koľkokrát bolo myšou kliknuté v rovnakej oblasti za krátky čas.
const handleClick = (e) => {
switch (e.detail) {
case 1:
console.log("click");
break;
case 2:
console.log("double click");
break;
case 3:
console.log("triple click");
break;
}
};
return <button onClick={handleClick}>Click me</button>;
V príklade vyššie, ak na tlačidlo kliknete trikrát, vytlačí všetky 3 prípady:
click
double click
triple click
Živá ukážka
Odpoveď č. 3
Požadovaný výsledok je možné dosiahnuť poskytnutím veľmi malého oneskorenia pri spustení normálnej akcie kliknutia, ktorá bude zrušená, keď nastane udalosť dvojitého kliknutia.
let timer = 0;
let delay = 200;
let prevent = false;
doClickAction() {
console.log(' click');
}
doDoubleClickAction() {
console.log('Double Click')
}
handleClick() {
let me = this;
timer = setTimeout(function() {
if (!prevent) {
me.doClickAction();
}
prevent = false;
}, delay);
}
handleDoubleClick(){
clearTimeout(timer);
prevent = true;
this.doDoubleClickAction();
}
< button onClick={this.handleClick.bind(this)}
onDoubleClick = {this.handleDoubleClick.bind(this)} > click me </button>
Odpoveď č. 4
Môžete použiť vlastný hook na spracovanie jednoduchého kliknutia a dvojitého kliknutia takto:
import { useState, useEffect } from 'react';
function useSingleAndDoubleClick(actionSimpleClick, actionDoubleClick, delay = 250) {
const [click, setClick] = useState(0);
useEffect(() => {
const timer = setTimeout(() => {
// simple click
if (click === 1) actionSimpleClick();
setClick(0);
}, delay);
// the duration between this click and the previous one
// is less than the value of delay = double-click
if (click === 2) actionDoubleClick();
return () => clearTimeout(timer);
}, [click]);
return () => setClick(prev => prev + 1);
}
potom vo vašej komponente môžete použiť :
const click = useSingleAndDoubleClick(callbackClick, callbackDoubleClick);
<button onClick={click}>clic</button>
Odpoveď č. 5
Upraviť:
Zistil som, že toto nie je problém v React 0.15.3.
Pôvodné:
Pre React 0.13.3, tu sú dva riešenia.
1. ref spätné volanie
Upozorňujeme, že aj v prípade dvojitého kliknutia bude obsluha jedného kliknutia vyvolaná dvakrát (raz pre každý klik).
const ListItem = React.createClass({
handleClick() {
console.log('single click');
},
handleDoubleClick() {
console.log('double click');
},
refCallback(item) {
if (item) {
item.getDOMNode().ondblclick = this.handleDoubleClick;
}
},
render() {
return (
<div onClick={this.handleClick}
ref={this.refCallback}>
</div>
);
}
});
module.exports = ListItem;
2. lodash debounce
Mal som ďalšie riešenie, ktoré používalo lodash, ale zanechal som ho kvôli zložitosti. Výhodou tohto bolo, že "click" sa volalo iba raz, a vôbec v prípade "double-click".
import _ from 'lodash'
const ListItem = React.createClass({
handleClick(e) {
if (!this._delayedClick) {
this._delayedClick = _.debounce(this.doClick, 500);
}
if (this.clickedOnce) {
this._delayedClick.cancel();
this.clickedOnce = false;
console.log('double click');
} else {
this._delayedClick(e);
this.clickedOnce = true;
}
},
doClick(e) {
this.clickedOnce = undefined;
console.log('single click');
},
render() {
return (
<div onClick={this.handleClick}>
</div>
);
}
});
module.exports = ListItem;
na kázeňskej skrini
Vážim si predstavu, že dvojité kliknutie nie je niečo, čo by sa dalo ľahko zistiť, ale či už lepšie alebo horšie, JE to paradigma, ktorá existuje a ktorú používatelia rozumejú kvôli jej rozšíreniu v operačných systémoch. Navyše, je to paradigma, ktorú moderné prehliadače stále podporujú. Až kým nebude odstránená zo špecifikácií DOM, môj názor je, že React by mal podporovať fungujúcu vlastnosť onDoubleClick spolu s onClick. Je nešťastné, že sa zdá, že to nepodporujú.