编写可拖拽的弹窗(代码片段)

author author     2023-02-03     300

关键词:

可拖拽的弹窗

在刚刚重构完的项目中使用到了element ui框架,踩了不少坑也学到了不少的东西。其中比较麻烦的是它的dialog弹窗组件是无法移动拖拽的,然而客户又强烈的要求一定要有这个功能,所以就自己写了个可拖拽的弹窗组件。虽然拖拽起来不是很流畅,但是也算是满足要求了。

1. 实现原理

主要的实现原理还是获取鼠标在div中的位置,获取位置后设置div的left和top来达到div跟随鼠标移动的效果。因为写的是vue,所以利用了vue的自定义指令来操作dom。

2. 实现步骤

2-1 设计盒子ui

  • 老实说,我经常被吐槽没有审美,设计的样式总是被喷。好在这次是dialog弹窗,网上有大把的参考样式。我大体参考了layer的弹窗做出了一个山寨弹窗。

    html代码
    ``` <template> <div class="m_showBox" :class="skin"> <div class="showBox_mask"></div> <div class="loading_wrap" v-if="buttonstatus === 1"></div> <div class="pop_box" id="pox-box" v-drag> <p class="pop_box_title"> title || "提示" <span class="pop_box_close" @click="cancel"></span> </p> <div class="pop_box_content"> <slot></slot> </div> <div class="pop_box_bottom"> <a href="javascript:;" class="cancel_btn" @click="cancel">canceltext || "取消"</a> <a href="javascript:;" class="confirm_btn" v-if="type === ‘confirm‘" :class="widths: buttonstatus === 1" @click="confirm"> <svg viewBox="25 25 50 50" class="u-circular" v-if="buttonstatus === 1"> <circle cx="50" cy="50" r="20" fill="none" class="path"></circle> </svg> <span :class="‘marginLeft‘: buttonstatus === 1">confirmtext || ‘确定‘</span> </a> </div> </div> </div> </template> ```
    css代码太长放到github上了vueDrag.vue
    效果图:
    ![](https://img2018.cnblogs.com/blog/1504647/201812/1504647-20181214210254482-1736032359.png)
  • 设计要点:
    1、背景遮罩
    我这里选择了使用了3个遮罩板,第一块是覆盖全屏幕的白色遮罩(m_showBox)使用fixed定位,让弹窗的所有内容与浏览器之间不会出现留白。第2块就是上图看到的灰色背景(showBox_mask),用来突显弹窗。最后一块是点击确定的遮罩窗(loading_wrap),来防止提交ajax时,用户点击按钮或修改弹窗数据。
    2、弹窗构成
    这里的弹窗就包括标题,内容和底部部分。内容部分通过插槽插入内容,底部按钮通过svg来实现提交加载的loading效果。

2-2 定义组件props

属性 描述
skin 用于控制弹窗的宽度(small, middle, large)
title 弹窗标题
type 弹窗类型
confirmtext 确认键文案
canceltext 取消键文案
buttonstatus 控制按钮加载效果

通过传入的props值来设置弹窗的样式和文案。

2-3 自定义事件实现按钮回调

  • confirm和cancel自定义事件
    定义自定义按钮事件,使用$emit触发。

    ``` methods: cancel: function () this.$emit("cancel"); , confirm: function () if (this.buttonstatus === 1) return; this.$emit("confirm"); , , ```

2-4 自定义指令drag实现拖拽效果

2-4-1 vue的directives。

通过vue自定义指令获取绑定的元素,在对DOM进行操作。关于更多vue自定义指令用法,移步自定义指令

2-4-2 相关属性(事件对象event,dom元素,window对象)。

  1. event.clientX:clientX事件属性返回当事件被触发时鼠标指针向对于浏览器可视区域的水平坐标。
  2. event.clientY:clientY事件属性返回当事件被触发时鼠标指针向对于浏览器页面可视区域的垂直坐标。
  3. offsetLeft/offsetLeftTop属性:可以返回当前元素距离某个定位父辈元素左边与顶部的距离(虽然我的父级遮罩层有了定位,但是它的宽高都是与body保持一致的)。
  4. offsetWidth/offsetHeight: 返回任何一个元素宽/高度,包括边框和填充
  5. window.innerHeight/Width: 获取当前页面可视区的宽高(包括滚动条)。

2-4-3 相关事件

事件 描述
onmousedown 鼠标按钮被按下。
onmousemove 鼠标被移动。
onmouseup/td> 鼠标按键被松开。

2-4-4 实现代码


directives: 
      drag: 
        inserted: function (el, binding, vnode) 
          vnode = vnode.elm;
          el.onmousedown = ((event) =&gt; 
            if (event.target.className !== "pop_box_title") 
              return;
            
            //获取鼠标在盒子中的位置
            let mouseX = event.clientX - vnode.offsetLeft;
            let mouseY = event.clientY - vnode.offsetTop;
            //绑定移动和停止函数
            document.onmousemove = ((event) =&gt; 
              let left, top;
              //获取新的鼠标位置对应下的盒子应该在的位置
              left = event.clientX - mouseX;
              top = event.clientY - mouseY;
              //获取div在页面中X轴的最小最大位置
              let minX = vnode.offsetWidth / 2;
              let maxX = (window.innerWidth - vnode.offsetWidth / 2) - 10//去掉滚动条的宽度
              if (left &lt;= minX) 
                left = minX;
               else if (left &gt;= maxX) 
                left = maxX;
              
              //获取div在页面中Y轴的最大最小位置
              let minY = vnode.offsetHeight / 2;
              let maxY = (window.innerHeight - vnode.offsetHeight / 2);
              if (top &lt;= minY) 
                top = minY;
               else if (top &gt;= maxY) 
                top = maxY;
              
              //赋值移动
              vnode.style.left = left + 'px';
              vnode.style.top = top + 'px';
           );
           document.onmouseup = (() =&gt; 
             document.onmousemove = document.onmouseup = null;
           );
         );
         window.onresize = (() =&gt;
            vnode.style.left = "50%";
            vnode.style.top = "50%";
         );
     
   

2-4-5 代码解析

1、给弹窗绑定onmousedown事件,获取到鼠标在弹窗中的位置(以弹窗左上角为原点)。
2、document绑定onmousemove事件,获取当前的鼠标位置,当前鼠标位置减去鼠标在弹窗的相当位置即可得到此时弹窗应该处于的位置。然后在通过style设置弹窗的位置。
3、鼠标松开解绑document的鼠标事件。
注意点:
  1. 弹窗要一直在页面可视区移动,最大的移动距离就是可视区的宽高减去盒子本身的宽高(还要考虑到浏览器的滚动条的宽高,我的浏览器滚动条是自己设置的,高度为0,宽度为10)。
    window.innerHeight - vnode.offsetHeight / 2;
    (window.innerWidth - vnode.offsetWidth / 2) - 10;
  2. 只有弹窗标题才能拖拽,所以判断非标题部分之间return。
  3. 浏览器窗口大小改变会影响弹窗的位置,监听改变浏览器窗口改变把弹窗居中。

2-5 使用

  1. 下载drag.vue。vueDrag.vue
  2. 使用import引入

    ``` import vDrag from "./dragDiv.vue" ```
  3. 控制弹窗的显示隐藏通过v-if绑定data里的数据即可。

    ``` <transition name="el-fade-in"> <v-drag v-if="isShow" :tilte="title" :type="type" @confirm="confirmSubmit" @cancel="cancel" :buttonstatus="buttonstatus"> <el-form label-width="100px"> <el-form-item label="用户名称:"> <el-input placeholder="请输入用户名" v-model="username"></el-input> </el-form-item> <el-form-item label="密码:"> <el-input placeholder="请输入密码" v-model="password"></el-input> </el-form-item> </el-form> </v-drag> </transition> ``` ![](https://img2018.cnblogs.com/blog/1504647/201812/1504647-20181214210304223-1376696165.png)

结语

关于这个组件我觉得还有很多优化的地方,望各位大佬给出意见。

原文地址:https://segmentfault.com/a/1190000017300044










kotlin实现从底部弹出带手势拖拽的列表弹窗的功能(代码片段)

实现:主工程项目要导入的第三方项目library,如下图:温馨提示:第三方项目library里面的不同弹窗有很多:从顶部弹窗、从底部弹窗、自由定位弹窗、自定义全屏弹窗、显示旋转弹窗(动画)…,适合工作,你想改什么样的弹窗... 查看详情

js+css+html点击登录后弹出可拖拽的模态框(代码片段)

js+css+html点击登录后弹出可拖拽的模态框1案例概述2编写HTML代码3编写CSS代码4编写JavaScript代码5总代码1案例概述我们经常能在网页上见到,当点击登录之后,就会弹出一个对话框,对话框中输入用户名和密码就可... 查看详情

js实现可拖拽的div

实现一个div可以被拖拽,代码如下所示:<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>zzw_drap</title><style>*{margin:0;padding:0;}#box{position:absolute;top:100 查看详情

移动端可拖拽的进度条

 原生js  移动端可拖拽的进度条效果图:代码:<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>干货-课程-完成</title><style>ul.lanren{margin:100pxauto;}.scal 查看详情

一统天下flutter(代码片段)

...:lib\\input\\drag.dart/**Draggable/DragTarget-拖拽**Draggable-按下后可拖拽的对象*LongPressDraggable-长按后可拖拽的对象*DragTarget-拖拽目标,可拖拽对象拖拽到DragTarget后可以有交互*/import\'package:flutter/material.dart\';import\'package:flutter_demo/helper.dart\... 查看详情

js中可拖拽的甘特图和流程图

甘特图:https://www.douban.com/note/441706674/https://www.uedsc.com/jquery-ganttview.htmlhttps://github.com/thegrubbsian/jquery.ganttViewhttp://download.csdn.net/detail/hspeed/5479645http://www.cnblogs.co 查看详情

117可拖拽弹窗

<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>Document</title><style>*padding:0;margin:0;html,bodyheight:100%;.outerBoxwidth:100%;height 查看详情

拖拽的效果第一步设置可拖拽的属性draggable="true"绑定drag事件第二步设置放置位置触发的事件dragover第三步设置放置之后

(function(){/*-------节点--------*/varmyimg=document.getElementById(‘myimg‘);vardropBox=document.getElementById(‘dropBox‘);/*-------事件绑定--------*/myimg.ondragstart=drag;dropBox.ondragover=dragover;dropB 查看详情

5分钟实现一个可拖拽矩形(代码片段)

...前面写这个原因很简单,有这么一个需求如下:编写代码实现以下要求:画一个矩形,拖拽矩形的4个角可以将矩形缩放,在矩形上按住鼠标拖动可以移动该矩形的位置。要求如下:整个矩形的最小大小为5p... 查看详情

nestable可拖拽树

...wangmj518/article/details/81746523 Nestable是基于Bootstrap的一个可拖拽的树结构表现插件。下面粗略的介绍一下它的用法,只作为学习参考,如有不合适之处,请各位凑合看。下图是我在现在系统中用到的Nestable,对系统模块排序。&nbs... 查看详情

android自定义view实现可拖拽的进度条

参考技术A在onSizeChanged方法中进行计算,这时可以得到一条与控件宽度相同的直线,并把路径设置给PathMeasure使用PathMeasure得出当前进度的路径并进行绘制,这里我将上一步的绘制放在了一起这个矩形的宽度需要我们用绘制最长的... 查看详情

可拖拽bottomsheetviewcontroller(代码片段)

当我们想弹出一个预览视图,bottomsheetmodalviewcontroller非常实用。在iOS中,长按拖拽手势可以让controller上滑或者向下消失。实现原理是,通过监听拖拽事件,动态改变view之间的autolayout约束,并加上少许动画。... 查看详情

android可拖拽view的简单实现(代码片段)

其实Android可拖拽View实现起来很简单,最简单的就是实现View的setOnTouchListener方法。下面这段代码就实现了如下两个功能:1、View随着手指的拖动儿拖动。2、当松开手指的时候,如果View在屏幕的右半边,则自动让其贴到屏幕右边... 查看详情

android可拖拽view的简单实现(代码片段)

其实Android可拖拽View实现起来很简单,最简单的就是实现View的setOnTouchListener方法。下面这段代码就实现了如下两个功能:1、View随着手指的拖动儿拖动。2、当松开手指的时候,如果View在屏幕的右半边,则自动让其贴到屏幕右边... 查看详情

androidactivity内实现可拖拽悬浮控件(代码片段)

效果图实现方式://在activity中重写此方法@OverrideprotectedvoidonPostCreate(@NullableBundlesavedInstanceState)super.onPostCreate(savedInstanceState);//添加一个悬浮Viewroot=findViewById(android.R.id.conte 查看详情

可拖拽listview基本使用技巧(dragsortlistview)

可拖拽的listview,DragSortListView这是gitHub上的一个开源项目。链接点击打开链接。这个开源控件主要是为了实现listview的item上下拖拽效果以便达到美化界面的作用。   先来看三张效果图。    第一张为初始的DragSortListView效... 查看详情

uniapp微信小程序和h5的弹窗滚动穿透解决(代码片段)

...着滚动了。如图所示ps:电脑端分鼠标滚轮滚动和长按鼠标拖拽滚动,手机端只有触屏滑屏滚动,即像电脑端的长按鼠标拖拽滚动我是在电脑上录屏的,所以两种情况的滚动穿透我都录上去鼠标滚轮滚动的穿透长按鼠标... 查看详情

可拖拽圆形进度条组件(支持移动端)(代码片段)

.katexdisplay:block;text-align:center;white-space:nowrap;.katex-display>.katex>.katex-htmldisplay:block;.katex-display>.katex>.katex-html>.tagposition:absolute;right:0px;.katexfont:1.21em/1.2Ka 查看详情