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

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

drag.jpg

相关事件: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;
}


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

相关阅读

通知

暂时关闭留言功能,正在开发相关插件。
后期不再更新mylog主题,对应补偿计划中。

精品域名

出售精品域名 Yumi.La 价格面议