可拖拽div实现细节示例与解析
可拖拽div实现细节示例与解析
最近有个后台的项目需要做一个翻译功能,有一个翻译框,后面要求这个翻译框可以随意拖动,于是想起之前在客户端上也做过一个类似的,本来打算直接超过来交差的,结果发现这里面的一些细节有点记不清了,导致抄完之后跟客户端的不太一样,有bug(向下拖动的时候会“跳走”),认真看代码后发现原来是有个细节漏了,这次特意写出来总结下。
为了简单省事,我就直接用项目里面的部分代码了(Vue版本)
<div class="translate_area" v-if="showTranslate" @dragstart="handleDragStart" @dragend="handleDragEnd" :style="translateBoxStyle">
<div class="translate_box">
<div class="translate_box_header" :style="{paddingBottom: paddingBottom}">
<div class="close_icon" @click="onTranslateClose"></div>
</div>
<div class="translate_box_body">
这里是主体部分
</div>
</div>
</div>
{
data() {
showMask: false,
translateBoxStyle: {
left: '200px',
top: '200px',
},
paddingBottom: 0,
translateBoxStartX: 0,
translateBoxStartY: 0,
},
methods: {
updateDragStyle() {
},
handleDragStart(e) {
this.showMask = true;
this.updateDragStyle(true);
this.translateBoxStartX = e.clientX;
this.translateBoxStartY = e.clientY;
},
handleDragEnd(e) {
let offsetX = parseInt(this.translateBoxStyle.left) + e.clientX - this.translateBoxStartX;
let offsetY = parseInt(this.translateBoxStyle.top) + e.clientY - this.translateBoxStartY;
this.translateBoxStyle.left = offsetX + 'px';
this.translateBoxStyle.top = offsetY + 'px';
this.showMask = false;
this.updateDragStyle(false);
},
}
}
translate_area用fixed定位,动态设置它的left、top来改变位置
基本原理
很容易想到的就是在drageStart和dragEnd事件回调里面进行处理,在drageStart里面记录下拖拽开始时鼠标的坐标,然后在drageEnd拿到拖拽结束时鼠标的坐标,它们的差值就是移动的位置的偏移量,这个差值+之前翻译框的left和top值,就是新的left和top值了。
效果如下(拖拽时故意把释放速度放慢了些)
细节部分
-
拖动时翻译框跳走的bug 上面就完了吗,当然不是,是有bug的,比如往下拖的时候,并且拖放位置在当前这个框的区域时,会突然跳走。
同时留意下拖拽过程中的残影,也就是图片中红框部分,它们的高度仅仅只是头部的高度
修复bug 想要解决上面“跳走”的bug,就要用到之前代码里面的
updateDragStyle
方法了。updateDragStyle(status) { let value = 0; if (status) { const container = document.querySelector('.translate_area'); if (container) { value = container.clientHeight + 2 + 'px'; } } else { value = 0; } this.paddingBottom = value; }
现在bug解决了,同时可以看到残影的范围变大了,几乎覆盖到整个翻译框区域了。残影算bug吗,我觉得有残影蛮好的玩的。
这里的paddingBottom怎么设置成了整个翻译框的高度?这看了后面的css部分就清楚了
-
showMask是做什么的 因为邮件一般用iframe展示的,用户在拖拽过程中可能会拖放到iframe区域,如果注释掉
showMash
逻辑也可能有bug,比如最后一次往上拖拽释放后也出现了“跳走”现在恢复
showMash
并加上深色背景色展示下利用一个全屏的蒙层,甚至合适的z-index,用它将所有可能的区域都挡住,避免拖拽释放的时候误进入到其它div或者被干扰
其它
前面提到了paddingBottom,拖拽的时候将为translate_box_header的div的padding-bottom设置成整个翻译框的高度,因为它本身的高度只有30px,通过padding-bottom把拖拽残影撑大,这样把上面的第一个bug给修复了。
.iframe_mask {
position: absolute;
background: #8c919d;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 998
}
.translate_area {
position: fixed;
width: 60%;
cursor: move;
z-index: 999;
}
.translate_box {
background: #fff;
color: initial;
z-index: 999;
border: 1px solid #ccc;
border-radius: 8px;
position: relative;
-webkit-user-drag: initial;
height: min-content;
}
.translate_box .translate_box_header {
position: absolute;
width: 100%;
height: 30px;
display: flex;
justify-content: flex-end;
align-items: center;
-webkit-user-drag: element;
}
.translate_box .translate_box_body {
margin-top: 30px;
padding: 12px;
border-top: 1px solid #ccc;
}
- 分类:
- Web前端