我正在使用React构建一个Minesweeper游戏,并希望在单击或双击单元格时执行不同的操作。目前,onDoubleClick
功能永远不会触发,显示来自onClick
的警报。如果我删除onClick
处理程序,则onDoubleClick
有效。为什么两个活动都不起作用?是否可以在元素上同时包含两个事件?
/** @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'));
答案 0 :(得分:46)
这不是React的限制,它是DOM click
和dblclick
事件的限制。正如Quirksmode的click documentation所建议的那样:
不要在同一元素上注册click和dblclick事件:无法区分单击事件和导致dblclick事件的点击事件。
有关更新的文档,dblclick
event上的W3C规范指出:
当在元素上单击指针设备的主按钮两次时,用户代理必须调度此事件。
双击事件必然会在两次点击事件后发生。
修改强>:
另一个建议的阅读是jQuery&#39; dblclick
handler:
不建议将处理程序绑定到同一元素的click和dblclick事件。触发的事件序列因浏览器而异,有些事件在dblclick之前接收到两个点击事件,而其他事件只接收一个事件。双击灵敏度(双击检测到的点击之间的最长时间)可能因操作系统和浏览器而异,并且通常可由用户配置。
答案 1 :(得分:14)
通过在触发正常点击操作时提供非常小的延迟,可以实现所需的结果,当双击事件发生时,该操作将被取消。
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>
答案 2 :(得分:13)
<强> 编辑: 强>
我发现这不是React 0.15.3的问题。
<强> 原件: 强>
对于React 0.13.3,这里有两个解决方案。
注意,即使在双击的情况下,单击处理程序也会被调用两次(每次单击一次)。
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;
我有另一个使用lodash
的解决方案,但由于其复杂性,我放弃了它。这样做的好处是“点击”只被调用一次,而在“双击”的情况下则完全没有。
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;
肥皂盒上的我很欣赏双击并不容易被检测到的想法,但无论好坏, IS 存在的范例和用户理解的范例,因为它在操作系统中很普遍。此外,它是现代浏览器仍然支持的范例。在从DOM规范中删除它之前,我的观点是React应该支持onDoubleClick
支持onClick
和// controller
public ActionResult Index()
{
model = new SampleViewModel();
model.Populate(database);
return View(model);
}
// view model
public class SampleViewModel
{
public SampleViewModel(DbContext db)
{
_list1 = context.Db.SqlQuery<SelectList1>("SELECT Id, Value FROM dbo.Table1").ToList();
_list2 = context.Db.SqlQuery<SelectList2>("SELECT Id, Value FROM dbo.Table2").ToList();
_list3 = context.Db.SqlQuery<SelectList3>("SELECT Id, Value FROM dbo.Table3").ToList();
_list4 = context.Db.SqlQuery<SelectList4>("SELECT Id, Value FROM dbo.Table4").ToList();
_list5 = context.Db.SqlQuery<SelectList5>("SELECT Id, Value FROM dbo.Table5").ToList();
}
private readonly List<SelectList1> _list1;
public int SelectedList1Id { get; set; }
public IEnumerable<SelectListItem> List1 { get { return new SelectList(_list1, "Id", "Value");} }
-//- _list2
-//- _list3
-//- _list4
-//- _list5
}
。不幸的是,他们似乎没有。
答案 3 :(得分:4)
您可以使用自定义钩子来处理简单的单击和双击:
function useSimpleAndDoubleClick(actionSimpleClick, actionDoubleClick, delay = 250) {
const [click, setClick] = useState(0);
useEffect(() => {
const timer = setTimeout(() => {
// simple click
if (click === 1) actionSimpleClick();
setClick(0);
}, 300);
// click in a delay < 250 = double click detected
if (click === 2) actionDoubleClick();
return () => {
clearTimeout(timer);
}
}, [click]);
return () => {
setClick(prev => prev + 1);
};
}
然后可以在组件中使用:
const click = useSimpleAndDoubleClick(callbackClick, callbackDoubleClick);
<button onClick={click}>clic</button>
答案 4 :(得分:3)
您可以使用 event.detail
来获取当前点击次数,而不是使用 ondoubleclick
。鼠标在同一区域内在短时间内被点击的次数。
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>;
在上面的例子中,如果你三次点击按钮,它将打印所有 3 个案例:
click
double click
triple click
答案 5 :(得分:1)
这就是我所做的。欢迎提出任何改进建议。
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>
</>
)
}
}
答案 6 :(得分:0)
这是基于Erminea解决方案的具有增量和识别值的like按钮的解决方案。
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>
)
答案 7 :(得分:0)
这是通过 Promise 实现相同目标的一种方法。 waitForDoubleClick
返回一个 Promise
,只有在没有执行双击时才会解析。否则会拒绝。时间可以调整。
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)
}
}