今天遇到这么一个问题:
我们在实现列表拖拽排序时使用了
react-sortable-hoc
这个库,确实很好用,利用ES装饰器新特性,几个@符号就解决了。但是因为我们在每一个列表item上还有菜单按钮,点击菜单按钮会弹出菜单,这样一来就会发现菜单的click事件和
react-sortable-hoc
的
mousedown
事件冲突了,特别是在你把pressDelay设置低于300ms时。
如果你使用过这个组件,你会发现pressDelay超过100ms,拖住体验就不再有丝滑般的感觉了。怎么办?我们需要完美啊,既要丝滑般的感觉又不要事件冲突。
假设在jQuery一把鎍的时代,这个都不是问题,因为菜单按键和列表item明显是父子元素的关系,我只需要把菜单上的mouse事件不向父元素listitem冒泡就解决了。
事实上时代并没有变化,react时代也是这么解决的。只是解决的时候会发现一个细节需要注意,那就是--
react事件机制和原生dom事件机制之男女有别
。
我们先来看
react-sortable-hoc
组件源码里是怎么绑定事件的
_utils.events.move.forEach(function (eventName) {
// 原生事件addEventListener
return _this.listenerNode.addEventListener(eventName,
_this.handleSortMove, false);
});
_utils.events.end.forEach(function (eventName) {
return _this.listenerNode.addEventListener(eventName, _this.handleSortEnd, false);
});
使用的是dom的addEventListener函数绑定事件,这走的是原生事件机制。
然后看我们在react项目中怎么去stop冒泡的
// 简单期间,只贴render函数足以
render() {
const { showMenu } = this.state;
const { children, className } = this.props;
const cls = classNames(styles['dropdown'], className);
return (
<div
className={cls}
ref={(el) => {
this.dropDown = el;
}}
{ // 这里直接绑定onMouseDown,走的是react的SyntheticEvent机制 }
onMouseDown={ (e) => e.stopPropagation()}
>
{ this.renderDropIcon() }
<Animate transitionName='fade' component='span'>
{ showMenu && this.renderDropDownMenu()}
</Animate>
</div>
);
}
在jsx模板里直接绑定onMouseDown/onMouseMove/onMouseUp事件,并调用
e.stopPropagation()
企图阻止冒泡。
然后你就发现完全没卵用啊,没道理啊,怎么会没有用呢?抓耳中...
这时候如果你在两个地方均加上log,你会发现竟然是
react-sortable-hoc
包裹的列表item的
mousedown
事件先触发,作为子元素的菜单后触发,更郁闷了有么有?
其实你通过本文的题目应该就猜到原因了。根本原因就是react的事件机制自成一套,具体可以看这篇文章
React事件机制
](
https://segmentfault.com/a/1190000008782645
)