D3元素添加Drag与Click事件冲突:首次点击需两次触发的问题排查
这个问题我之前也碰到过!原因其实是D3的拖拽(drag)行为会默认拦截第一次点击事件——当你首次点击元素时,拖拽的start事件会触发,并且D3内部会阻止原生点击事件的传播,所以你的showTipArrow根本没被调用;而第二次点击时,因为没有触发拖拽的start(或者说拖拽行为已经完成了一次周期),点击事件才正常生效。
接下来给你两种可行的解决方案:
方案一:用drag.filter()区分拖拽和点击
通过过滤函数,只有当鼠标移动超过一定阈值时才触发拖拽,否则让点击事件正常执行:
d3.select('#points').append('use') .attr('id', 'red_'+thisId) .attr('class', 'point-create') .attr('xlink:href','#point') .on('click',showTipArrow) .call(d3.drag() .filter(function(event) { // 这里设置2px的阈值,你可以根据需求调整 return Math.abs(event.dx) > 2 || Math.abs(event.dy) > 2; }) .on('start', dragstarted) .on('drag', dragged) .on('end', dragended)); function showTipArrow(){ console.log('6666');}
方案二:在拖拽结束时判断是否为点击
记录拖拽开始时的鼠标位置,在dragended里判断如果移动距离极小,就手动调用点击回调:
// 先定义变量记录拖拽起始位置 let startPos = {}; function dragstarted(event) { startPos.x = event.x; startPos.y = event.y; // 这里放你原本的dragstarted逻辑 } function dragended(event) { // 判断是否是点击(移动距离小于2px) const isClick = Math.abs(event.x - startPos.x) < 2 && Math.abs(event.y - startPos.y) < 2; if (isClick) { // 调用点击回调,注意用call保持this指向当前元素 showTipArrow.call(this); } // 这里放你原本的dragended逻辑 } // 事件绑定部分不变 d3.select('#points').append('use') .attr('id', 'red_'+thisId) .attr('class', 'point-create') .attr('xlink:href','#point') .on('click',showTipArrow) .call(d3.drag() .on('start', dragstarted) .on('drag', dragged) .on('end', dragended)); function showTipArrow(){ console.log('6666');}
这两种方法都能解决首次点击需要两次操作的问题,你可以根据自己的场景选一个更合适的~
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

