Ich baue ein Minesweeper-Spiel mit React und möchte eine andere Aktion ausführen, wenn eine Zelle einfach oder doppelt angeklickt wird. Derzeit wird die onDoubleClick
Funktion niemals ausgelöst, der Alarm von onClick
wird angezeigt. Wenn ich den onClick
Handler entferne , onDoubleClick
funktioniert. Warum funktionieren nicht beide Veranstaltungen? Ist es möglich, beide Ereignisse auf einem Element zu haben?
/** @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'));
javascript
reactjs
thisisnotabus
quelle
quelle
dblclick
Ereignis auszulösen . In meiner Antwort erfahren Sie, warum es nicht möglich ist, den ersten Klick zu verhindern.Antworten:
Dies ist keine Einschränkung von React, sondern eine Einschränkung der DOMs
click
unddblclick
Ereignisse. Wie von Quirksmode vorgeschlagenen Klick Dokumentation :Eine aktuellere Dokumentation finden Sie in der W3C-Spezifikation des
dblclick
Ereignisses :Ein Doppelklickereignis tritt notwendigerweise nach zwei Klickereignissen auf.
Bearbeiten :
Eine weitere empfohlene Lektüre ist der
dblclick
Handler von jQuery :quelle
Das erforderliche Ergebnis kann erzielt werden, indem beim Auslösen der normalen Klickaktion eine geringfügige Verzögerung vorgesehen wird, die abgebrochen wird, wenn das Doppelklickereignis eintritt.
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>
quelle
Bearbeiten:
Ich habe festgestellt, dass dies kein Problem mit React 0.15.3 ist.
Original:
Für React 0.13.3 sind hier zwei Lösungen.
1. Ref Rückruf
Beachten Sie, dass der Einzelklick-Handler auch bei Doppelklicks zweimal aufgerufen wird (einmal für jeden Klick).
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 entprellen
Ich hatte eine andere Lösung, die verwendet wurde
lodash
, aber ich habe sie wegen der Komplexität aufgegeben. Dies hatte den Vorteil, dass "Klick" nur einmal aufgerufen wurde und bei "Doppelklick" überhaupt nicht.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;
auf der Seifenkiste
Ich schätze die Idee , dass Doppelklick etwas nicht leicht zu erkennen, aber für besser oder schlechter es IST ein Paradigma , das und ein solches vorhanden ist, dass die Nutzer in Betriebssystemen aufgrund ihrer Prävalenz verstehen. Darüber hinaus ist es ein Paradigma, das moderne Browser immer noch unterstützen. Bis zu dem Zeitpunkt, an dem es aus den DOM-Spezifikationen entfernt wird, sollte React meiner Meinung nach eine funktionierende
onDoubleClick
Requisite unterstützenonClick
. Es ist bedauerlich, dass dies anscheinend nicht der Fall ist.quelle
Sie können einen benutzerdefinierten Haken verwenden, um einfaches Klicken und Doppelklicken wie folgt zu handhaben:
function useSimpleAndDoubleClick(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); }
Dann können Sie in Ihrer Komponente Folgendes verwenden:
const click = useSimpleAndDoubleClick(callbackClick, callbackDoubleClick); <button onClick={click}>clic</button>
quelle
Folgendes habe ich getan. Verbesserungsvorschläge sind willkommen.
class DoubleClick extends React.Component { state = {counter: 0} handleClick = () => { this.setState(state => ({ counter: this.state.counter + 1, })) } handleDoubleClick = () => { this.setState(state => ({ counter: this.state.counter - 2, })) } render() { return( <> <button onClick={this.handleClick} onDoubleClick={this.handleDoubleClick> {this.state.counter} </button> </> ) } }
quelle
Dies ist die Lösung einer ähnlichen Schaltfläche mit Inkrement- und Unterscheidungswerten basierend auf der Lösung von Erminea.
useEffect(() => { let singleClickTimer; if (clicks === 1) { singleClickTimer = setTimeout( () => { handleClick(); setClicks(0); }, 250); } else if (clicks === 2) { handleDoubleClick(); setClicks(0); } return () => clearTimeout(singleClickTimer); }, [clicks]); const handleClick = () => { console.log('single click'); total = totalClicks + 1; setTotalClicks(total); } const handleDoubleClick = () => { console.log('double click'); if (total > 0) { total = totalClicks - 1; } setTotalClicks(total); } return ( <div className="likeButton" onClick={() => setClicks(clicks + 1)} > Likes | {totalClicks} </div> )
quelle
Hier ist ein Weg, um dasselbe mit Versprechungen zu erreichen.
waitForDoubleClick
Gibt ein zurück,Promise
das nur aufgelöst wird, wenn kein Doppelklick ausgeführt wurde. Andernfalls wird es abgelehnt. Die Zeit kann angepasst werden.async waitForDoubleClick() { return new Promise((resolve, reject) => { const timeout = setTimeout(() => { if (!this.state.prevent) { resolve(true); } else { reject(false); } }, 250); this.setState({ ...this.state, timeout, prevent: false }) }); } clearWaitForDoubleClick() { clearTimeout(this.state.timeout); this.setState({ prevent: true }); } async onMouseUp() { try { const wait = await this.waitForDoubleClick(); // Code for sinlge click goes here. } catch (error) { // Single click was prevented. console.log(error) } }
quelle