目标
1,position:absolute实现一个可以拖拽的图片,从位置A拖动到位置B
2,transform实现一个可以拖拽的图片,跟着鼠标移动,释放鼠标后图片回到初始位置
前言
拖拽的事件:
- 针对被拖拽的元素:
- onDragStart:开始拖拽元素
- onDrag:元素拖拽中
- onDragEnd:结束拖拽元素
- 针对目标元素:
- onDragEnter:拖拽的元素进入到目标元素时触发
- onDragLeave:拖拽的元素移出目标元素时触发
- onDragOver:拖拽的元素在目标元素(容器)范围内拖拽时触发
解决拖拽过程中出现小的缩略图和黑色禁止符号的问题:-webkit-user-drag和draggable
笔者是基于react和ant design,其他框架(或没用框架)也是一样的使用。
一、实现目标:position:absolute将图片从位置A拖动到位置B
笔者这里使用的是绝对定位(position:absolute),原理就是通过改变top和left来修改图片的位置。如果初始位置是固定需要通过bottom和right定位的,可以先转成top和left,例如:
let h =
window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight;
let w =
window.innerWidth ||
document.documentElement.clientWidth ||
document.body.clientWidth;
setLeft(w - 352);
setTop(h - 295);
首先获取可视窗口的宽高,用这个宽减去图片的(宽+右边距)即可得到left,高度亦如此,得出top的值,笔者这里为了满足其他需求,在img外层套了个div,设置样式如下:
<div
style={{
position: "absolute",
width: "332px",
height: "235px",
top: `${top}px`,
left: `${left}px`,
zIndex: 999,
}}
onDragStart={(e) => handleDragStart(e)}
onDragEnd={(e) => handleDragEnd(e)}
>
<img
src={imageSrc}
style={{
width: "332px",
height: "235px",
}}
onClick={() => {}}
/>
</div>
当鼠标开始拖动时,在onDragStart中记录当前鼠标点击的位置,当鼠标停止拖动时,在onDragEnd中获取两次鼠标位置之差,这个差也就是两次left之差,得出最新的left值,top亦是如此:
const handleDragStart = (e) => {
setClickLeft(e.clientX);
setClickTop(e.clientY);
};
const handleDragEnd = (e) => {
setLeft(left - clickLeft + e.clientX);
setTop(top - clickTop + e.clientY);
};
现在,已经实现将图片从A拖到B的需求,但还要些优化,例如鼠标拖动过程中,显示了黑色禁止图标(cursor),这是因为当我们把拖拽元素拖动到其他地方(目标元素),但目标元素不允许这种行为,所以在目标元素上设置如下:
onDragEnter={(e) => e.preventDefault()}
onDragLeave={(e) => e.preventDefault()}
onDragOver={(e) => e.preventDefault()}
现在黑色的禁止图标已经没有了。
针对拖拽过程中img会出现小的缩略图的问题,针对img设置WebkitUserDrag(对应css的-webkit-user-drag)为none,会发现这时不可拖拽了,不要慌,这是因为外层的div和img尺寸一样,img作为里层元素不可拖拽,但是只需要在div上加上draggable={true},此时会发现又可以拖拽了,且小的缩略图已经没有了,取而代之的是与img尺寸相同的图片,这是因为拖拽的是整个div,img是div内的元素,所以这个图其实是div的内容。
二、实现目标:transform实现图片跟着鼠标移动,释放鼠标后图片回到初始位置
笔者这里使用的是绝对定位和transform,通过设置偏移量改变图片的位置。这里鼠标移动的距离就是偏移量,因为需要根据鼠标移动,所以加上事件onDrag,代码如下:
const handleDragStart = (e) => {
setClickLeft(e.clientX);
setClickTop(e.clientY);
e.dataTransfer.effectAllowed = "move";
};
const handleDrag = (e) => {
e.preventDefault && e.preventDefault();
setTranslateX(e.clientX - clickLeft);
setTranslateY(e.clientY - clickTop);
};
const handleDragEnd = (e) => {
setTranslateX(0);
setTranslateY(0);
};
根据上文,我们可以很自然的将拖拽元素加上onDragStart和onDragEnd事件,在目标元素上设置onDragEnter、onDragLeave和onDragOver达到拖拽过程中不显示黑色禁止图标的目的。通过draggable={true}和img设置WebkitUserDrag达到去掉拖拽过程中缩略图的效果。
<div
className="ant-image-preview-img-wrapper"
style={{
transform: `translate3d(${translateX}px, ${translateY}px, 0px)`,
}}
onDragStart={(e) => handleDragStart(e)}
onDrag={(e) => handleDrag(e)}
onDragEnd={(e) => handleDragEnd(e)}
draggable={true}
>
<img
className="ant-image-preview-img"
src={currentSrc}
style={{
WebkitUserDrag: "none",
}}
/>
</div>
总结
本篇介绍了两种拖拽图片的方法:
- position设置绝对定位,通过修改left和top可以实现将图片从位置A拖动到位置B,也可以实现图片跟着鼠标移动,释放鼠标后图片回到初始位置;
- position设置绝对定位,加上transform,通过修改x和y的偏移量实现图片跟着鼠标移动,释放鼠标后图片回到初始位置,也可以实现将图片从位置A拖动到位置B。
读者可以根据实际情况甄选使用,如有其他建议,欢迎讨论!