道招

可拖拽div实现细节示例与解析

如果您发现本文排版有问题,可以先点击下面的链接切换至老版进行查看!!!

可拖拽div实现细节示例与解析

最近有个后台的项目需要做一个翻译功能,有一个翻译框,后面要求这个翻译框可以随意拖动,于是想起之前在客户端上也做过一个类似的,本来打算直接超过来交差的,结果发现这里面的一些细节有点记不清了,导致抄完之后跟客户端的不太一样,有bug(向下拖动的时候会“跳走”),认真看代码后发现原来是有个细节漏了,这次特意写出来总结下。

file

为了简单省事,我就直接用项目里面的部分代码了(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来改变位置

基本原理

很容易想到的就是在drageStartdragEnd事件回调里面进行处理,在drageStart里面记录下拖拽开始时鼠标的坐标,然后在drageEnd拿到拖拽结束时鼠标的坐标,它们的差值就是移动的位置的偏移量,这个差值+之前翻译框的left和top值,就是新的left和top值了。

效果如下(拖拽时故意把释放速度放慢了些)

细节部分

  • 拖动时翻译框跳走的bug 上面就完了吗,当然不是,是有bug的,比如往下拖的时候,并且拖放位置在当前这个框的区域时,会突然跳走。

    同时留意下拖拽过程中的残影,也就是图片中红框部分,它们的高度仅仅只是头部的高度

    file

    修复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;
}
更新时间:
上一篇:HarmonyOS NEXT上线应用/元服务注意事项,运动健康转换工具替大家踩坑了下一篇:markdown+NextJS搭建个人博客

相关文章

关注道招网公众帐号
友情链接
消息推送
道招网关注互联网,分享IT资讯,前沿科技、编程技术,是否允许文章更新后推送通知消息。
允许
不用了