chrome 下鼠标点击BUG!!!! 涉及 mousedown, mousemove, mouseup

事情缘由,正在做echarts的关系图,想要实现节点拖动,但echarts自带的事件无法满足拖动效果,顾想到原生js的addEventListenerremoveEventListener,来自己写一个拖动效果出来,可是!!!!!
万恶的chrome有bug、、、
拖动的写法:对元素添加mousedown mouseup,然后在down回调函数里加入mousemove,在up回调函数里移除mousemove,这样就可以实现拖动元素的效果。
代码复现:

var canvas = document.getElementsByTagName('canvas')[0]
canvas.addEventListener('mousedown', function (e) {
console.log('mousedown');
canvas.addEventListener('mousemove', function (e) {
console.log('mousemove');
})
})
canvas.addEventListener('mouseup', function (e) {
console.log('mouseup');
canvas.removeEventListener('mousemove', function (e) {
console.log('remove mousemove');
})
console.log(canvas);
})

bug现场图

至于这个问题怎么解决:
我搜了半天...
最终找到这个帖子,说的很详尽👇

// 在Chrome下有一个关于mousemove的bug是:
// 1.在触发mouseup事件时,包括在触发click和contextmenu时,也会触发mousemove事件;
// 2.更诡异的是,当你连续的触发contextmenu事件时,mousedown事件会被mousemove代替,
// 目前我想到的一个解决方案,通过时间戳比较:
var body = document.querySelector("h1");
var timeStamp;
body.addEventListener("mousedown", function (e) {
console.log("mouse down");
}, false);
body.addEventListener("mouseup", function (e) {
console.log("mouse up");
timeStamp = e.timeStamp;
})
body.addEventListener("mousemove", function (e) {
if (!timeStamp || ( e.timeStamp - timeStamp > 10)) {
console.log("mouse move");
}
})
// 这样能避免在触发click事件,或者触发鼠标左键mouseup引起的mousemove,但是对于上面描述的contextmenu引起的mousemove还是不能很好解决

上文链接

最终我的代码实现

var move = {
offsetX: 0,
offsetY: 0
}
var canvas = document.querySelector('canvas')
canvas.addEventListener('mousedown', function (e) {
// console.log('mousedown', e);
move.offsetX = e.offsetX
move.offsetY = e.offsetY
}, false)
canvas.addEventListener('mouseup', function (e) {
console.log('mouseup', e);
move.offsetX = 0
move.offsetY = 0
})
canvas.addEventListener('mousemove', debounce(function (e) {
// console.log(e.offsetX, move.offsetX);
var offsetX = e.offsetX - move.offsetX
var offsetY = e.offsetY - move.offsetY
console.log('xChange: ' + offsetX, 'yChange: ' + offsetY);
}, 12, true))
/**
* 防反跳。fn函数在最后一次调用时刻的delay毫秒之后执行!
* @param fn 执行函数
* @param delay 时间间隔
* @param isImmediate 为true,debounce会在delay时间间隔的开始时立即调用这个函数
* @returns {Function}
*/
function debounce(fn, delay, isImmediate) {
var timer = null; //初始化timer,作为计时清除依据
return function () {
var context = this; //获取函数所在作用域this
var args = arguments; //取得传入参数
clearTimeout(timer);
if (isImmediate && timer === null) {
//时间间隔外立即执行
fn.apply(context, args);
timer = 0;
return;
}
timer = setTimeout(function () {
fn.apply(context, args);
timer = null;
}, delay);
}
}
posted @   lambertlt  阅读(429)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
历史上的今天:
2021-06-09 springMvc 实现跨域以及跨站
2020-06-09 计算机科学与技术易错知识点需记篇
点击右上角即可分享
微信分享提示