JS做DOM节点实时拖动拖拽的一些坑

大坑:监听DOM不对,导致拖动会失效。

相关事件:onmousedown、onmousedown、onmousemove

例如,有DOM对象demo,我们要实现demo的拖动,就需要对它监听onmousedown事件,用于触发拖动的开始。

var demo = document.getElementById('#demo');
demo.addEventListener('mousedown',function(e) {
    console.log('成功监听demo的鼠标按下事件')
});

嗯,这样自然就死监听成功了,很多朋友都会继续给demo监听onmousemove和onmouseup事件啦。理论上来说,监听继续给demo监听这两个事件是没问题的,但是我们在实际操作中会发现,demo移动着突然移动不了。而且,明显能感觉demo与鼠标的移动直接有延迟。没错,就是这个延迟导致了移动突然中止。因为延迟的时候,鼠标已经移出了demo的范围,导致onmousemove事件监听中断。*PS:没有屏蔽延迟的方法,延迟是事件的冒泡与捕获产生,自然就不能真正意义上的实时监听到对应事件。

解决方法其实就很简单了,我们拖动的demo是放在document中的,我们监听document的onmousemove事件就能避开范围移除问题(如果移出了浏览器范围,就是硬伤了)。

var demo = document.getElementById('#demo');
demo.addEventListener('mousedown',function(e) {
    console.log('成功监听demo的鼠标按下事件');
});
document.addEventListener('mousemove',function(e) {
    console.log('正在拖动','X:',e.clientX);
    console.log('正在拖动','Y:',e.clientY);
    // 我们通过监听e.clientX和e.clientY做demo的移动
});
document.addEventListener('mouseup',function(e) {
    console.log('鼠标松开啦');
});

但是有些朋友会发现,监听到document上的话,demo就不听话了,所以需要对他们加一个状态,或者通过添加事件移除事件来对demo的拖动进行监听。

// 方案一
var demo = document.getElementById('#demo');
var move_status = false;
demo.addEventListener('mousedown',function(e) {
    console.log('成功监听demo的鼠标按下事件');
    move_status = true;
});
document.addEventListener('mousemove',function(e) {
    if (!move_status) return;
    console.log('正在拖动','X:',e.clientX);
    console.log('正在拖动','Y:',e.clientY);
    // 我们通过监听e.clientX和e.clientY做demo的移动
});
document.addEventListener('mouseup',function(e) {
    move_status = false;
    console.log('鼠标松开啦');
    // 我们在这里处理最后的计算,然后将demo放到对应位置
});

// 方案二
var demo = document.getElementById('#demo');
// 拖动处理方法
var move_handler = function(e) {
    console.log('正在拖动','X:',e.clientX);
    console.log('正在拖动','Y:',e.clientY);
    // 我们通过监听e.clientX和e.clientY做demo的移动
}
// 拖动结束处理方法
var move_end = function(e) {
    console.log('鼠标松开啦');
    // 我们在这里处理最后的计算,然后将demo放到对应位置
    document.removeEventListener('mousemove',move_handler);
    document.removeEventListener('mouseup',move_end);
}
// 监听鼠标按下触发拖动
demo.addEventListener('mousedown',function(e) {
    console.log('成功监听demo的鼠标按下事件');
    document.addEventListener('mousemove',move_handler);
    document.addEventListener('mouseup',move_end);
});

解决这些问题以后,大家在拖动的时候,还会发现,拖动的时候,demo中的文本与其它节点文本会被选中,很影响我们操作体验。解决方法很取巧,就是在拖动开始的时候,给全局加上一些css内容,防止文本被选中。

.none-select {
    -moz-user-select: none;
    -webkit-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

当然,这上面都是我为文章总结出来的代码案例,并非实际项目中的代码。实际项目中,我们可以借助jQuery完成更好的dom操作管理。在实际的使用中,我们需要写更完善的方法,下面我贴出一段项目代码,因为代码是项目中的代码片段,不能直接拿来用哦。

/**
 * moveContentItemWatch - 移动文章节点
 */
XXXXXX.prototype.moveContentItemWatch = function(selector) {
    var _this = this;
    var activeMoveWatch;
    $(document).on('mousedown',selector,function(e) {
        _this.data._startX = e.clientX;
        _this.data._startY = e.clientY;
        _this.data._moveItem = $(this);
        _this.data._moveParentNode = $(this).parent();
        _this.data._moveSelector = selector;
        activeMoveWatch = setTimeout(function() {
            if (_this.status.editing) return;
            _this.status.moveItem = true;
        },300);
    }).on('mousemove',function(e) {
        if (!_this.status.moveItem) return;
        _this.data._moveX = e.clientX;
        _this.data._moveY = e.clientY;
        _this.handlerItemMove('move');
    }).on('mouseup',function(e) {
        clearTimeout(activeMoveWatch);
        if (_this.status.moveItem) {
            _this.handlerItemMove('end');
        }
    });

    return this;
}


阅读: 1548
在同意共创许可协议(CC BY-NC-SA-4.0)的前提下,您可以转载本文。
橙色阳光
https://oss.so/article/81

相关阅读

留言评论

暂无留言
关于各种NPM问题,推荐使用Yarn,安装速度快,没用各种奇葩的错误,方便快捷。
收集的NodeJS代码片段: NodeJS Tools

最新留言

  • soshine 在《ZBlogPHP外链插件免费送!独家免费插件!》中留言
    很好的插件,如果能更自动化一点就好了,自动将淘宝客外链转换成对应的文章ID形式。
  • 橙色阳光 在《纯Javascript实现淡入淡出效果》中留言
    讲真,我现在的淡入淡出都是用css3+setTimeout了,用这个方案也是当年的一些想法。
  • 橙色阳光 在《基于jQuery的简易幻灯插件 - OsSliderJS》中留言
    讲真,这段JS大家不要看了……
  • BeautifulDays 在《三年了,我依然还在》中留言
    兴趣变工作,工作成为一种乐趣。这也蛮好的啊,工作之余可以在优化自己的博客,在博客上分享自己的一些心得、知识,毕竟,博客,现在已经越来越多的被今日头条,新浪微博,腾讯微博、微信公众号等第三方自营体APP取代了。能坚持下去的真不容易。给你一个赞!
  • 柒柒 在《移动端Touch事件preventDefault以后影响click事件触发的不科学解决方案》中留言
    先赞再说
  • 大谋 在《Chrome内核对css中rem大小单位文本font-size处理BUG参考解决方案》中留言
    还是你这里好看