JavaScript实现元素拖动性能优化
前言:前几天没事干写了个小网站,打算用原生的javascript实现元素的拖动,但是事情并没有想象的那么顺利,首先是实现了拖动的元素卡的不能再卡,简直不能够,上图~~
看见没?这就是效果,简直让人欲哭无泪啊,查了大量的资料也无济于事,根本就没有人会遇到过这个问题,但是经过N次试验,终于找到了原因——竟然是我给这个元素添加了transition属性导致的,元凶:
去掉这个属性之后,就变得完全不一样了
至于原因,我现在也不知道为什么,很无奈╮(╯▽╰)╭
接下来就是性能优化了,我原来的实现方式是给元素添加一个mousemove事件,然后判断事件对象的buttons是否为1,如果是1的话表明此时左键按下,然后记录此时鼠标的x和y的坐标,当下次触发mousemove事件的时候用当前鼠标的位置减去上次记录的鼠标的位置就是鼠标移动的距离,然后用元素当前的位置加上鼠标移动的距离就实现了拖动,代码如下:
//实现拖动 var lastClientX = 0; var lastClientY = 0; var count = 0; addCommandCard.addEventListener('mousemove', function() { if(arguments[0].buttons == 1) { addCommandCard.style.cursor = "default"; arguments[0].preventDefault(); if(count == 0) { lastClientX = arguments[0].clientX; lastClientY = arguments[0].clientY; count++; } else { addCommandCard.style.left = addCommandCard.offsetLeft + arguments[0].clientX - lastClientX + "px"; addCommandCard.style.top = addCommandCard.offsetTop + arguments[0].clientY - lastClientY + "px"; lastClientX = arguments[0].clientX; lastClientY = arguments[0].clientY; count++; } } });
今天看了个实现拖动的代码,基本思路是,给元素添加mousedown事件,在这个事件处理程序中,首先记录当前鼠标的位置与元素的offsetLeft和offsetTop的差值,然后给document添加mousemove和mouseup事件,在document的mousemove事件中,将元素的left设置为当前鼠标X坐标减去上面记录的鼠标X坐标和元素offsetLeft的差值,top值设置为当前鼠标Y坐标减去上面记录的鼠标Y坐标和元素offsetTop的差值,在mouseup事件中,设置document的mousemove和mouseup为null,上面的话可能有些拗口,通俗点说就是首先记录元素的左边框和鼠标X坐标的差值,然后记录元素的上边框和鼠标Y坐标的差值,在鼠标移动的时候将元素的左边框的值设置为鼠标当前X坐标的值减去鼠标和元素左边框之间的相对距离,上边框类似,因为在元素拖动的过程中,鼠标和元素的相对位置始终没有发生变化,所以只要用鼠标当前的位置减去鼠标和元素之间的相对距离就是元素拖动后的位置,代码:
//实现拖动 addCommandCard.addEventListener('mousedown', function() { arguments[0].preventDefault(); var disX = arguments[0].clientX - addCommandCard.offsetLeft; var disY = arguments[0].clientY - addCommandCard.offsetTop; document.onmousemove = function() { addCommandCard.style.left = arguments[0].clientX - disX + 'px'; addCommandCard.style.top = arguments[0].clientY - disY + 'px'; } document.onmouseup = function() { document.onmousemove = null; document.onmouseup = null; } });
总结:在chrome中测试结果表明,两种拖动方式都可以稳定在60fps,总得来说,差别不大,但是第一种有比较慢明显的缺点,首先,第一种给元素添加了mousemove事件,那就意味着不管元素当前是否拖动,只要有鼠标移动到元素上,这个事件就不断的触发,虽然只有一条判断语句,但是造成性能的白白浪费,而第二种是添加了mousedown事件,只有鼠标按下的时候才会触发,所以没有这个问题,但是,如果在别处给document指定了mousemove和mouseup事件,那么在元素拖动开始和结束之后,这些事件处理程序会变得无效,因为覆盖的原因,但是可以通过DOM2级事件处理程序来解决,不算大问题