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 @ 2022-06-09 11:41  lambertlt  阅读(464)  评论(0)    收藏  举报