chrome 下鼠标点击BUG!!!! 涉及 mousedown, mousemove, mouseup
事情缘由,正在做echarts的关系图,想要实现节点拖动,但echarts自带的事件无法满足拖动效果,顾想到原生js的addEventListener
和removeEventListener
,来自己写一个拖动效果出来,可是!!!!!
万恶的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); } }
有什么不同见解可以在评论区共同讨论
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2021-06-09 springMvc 实现跨域以及跨站
2020-06-09 计算机科学与技术易错知识点需记篇