最近在用vue3重构后台的一个功能。一个弹窗组件,弹出一个表单。然后点击提交。

早上运维突然跑过来问我,为啥弹窗挡住了下边的表格的数据,我添加的时候,都没法对照表格来看了。你必须给我解决一下。

我参考了一下几大Vue的ui组件库。发现element iview antv。好像都没这个功能。为啥运维需要这个功能??

但是没办法,只能整一个就是了。

做之前本来想直接做到dialog这个组件中。但是又担心后面其他的组件会用到。于是决定把拖拽功能做到指令中。

整个功能点如图。鼠标在拖拽区域拖动,整个对话框在浏览器可视范围内移动。

Drag指令主要实现思路

  1. 在指令挂载的时候,监听当前html节点的鼠标点击事件

  2. 然后在点击当前html节点的时候,判断是否点击在drag-target这个class所在的子节点上。如果是,那么触发document鼠标移动事件。然后计算出鼠标移动距离,对应修改弹出框的left值和top值。并记录下当前按下的位置x和y

    let x = e.clientX;
    let y = e.clientY;
  3. 如何限制拖动的节点只能在屏幕内移动,不能移动出屏幕呢?

    1. 限制left不能小于0,在定位为position: fixed 的时候,left如果小于0,那么html节点的左侧肯定已经在显示区域外了。那么我们不能让left小于0

      let bodyW = document.body.clientWidth;
      let bodyH = document.body.clientHeight; let left = elLeft - (x - move.clientX);
      if (left < 0) {
      left = 0;
      }
    2. 限制left不能大于可视区域的宽度减去当前html节点的宽度,如果left大于这个宽度,那么当前html节点肯定右侧已经处于显示区域的右侧外边了

      if (left > bodyW - el.offsetWidth) {
      left = bodyW - el.offsetWidth;
      }
    3. 上下拖拽位置限制和左右拖拽限制思路是一样,只要保证top的值大于0且小于屏幕可视范围的高度减去当前html节点的高度,那么拖动就无法拖出屏幕了。

      let top = elTop - (y - move.clientY);
      if (top < 0) {
      top = 0;
      }
      if (top > bodyH - el.offsetHeight) {
      top = bodyH - el.offsetHeight
      }

    drag指令完整代码

    import { App } from 'vue';
    
    export default {
    install(Vue: App<Element>) {
    Vue.directive('drag', {
    mounted(el: HTMLElement, bind) {
    el.onmousedown = (e) => {
    let elLeft = el.offsetLeft;
    let elTop = el.offsetTop;
    let dom = <HTMLElement>e.target;
    if (dom.classList.contains('drag-target')) {
    let x = e.clientX;
    let y = e.clientY;
    document.onmousemove = (move: MouseEvent) => {
    let bodyW = document.body.clientWidth;
    let bodyH = document.body.clientHeight; let left = elLeft - (x - move.clientX);
    if (left < 0) {
    left = 0;
    }
    if (left > bodyW - el.offsetWidth) {
    left = bodyW - el.offsetWidth;
    }
    el.style.left = left + 'px'
    let top = elTop - (y - move.clientY);
    if (top < 0) {
    top = 0;
    }
    if (top > bodyH - el.offsetHeight) {
    top = bodyH - el.offsetHeight
    }
    el.style.top = top + 'px' document.onmouseup = (up: MouseEvent) => {
    document.onmousemove = null;
    document.onmouseup = null
    }
    if (window.getSelection()) {
    window.getSelection()?.removeAllRanges()
    }
    }
    }
    }
    },
    unmounted(el, bind) {
    el.onmousedown = null;
    } })
    }
    }

    使用

    import DragDirective from './DragDirective'
    
    createApp(App).use(DragDirective).mount('#app')
    
    

    注册指令到Vue App上,然后在需要移动的html节点上加上 v-drag ,并在触发拖拽的子节点的class上,加上drag-target

    <div
    class="f-dialog"
    v-if="show"
    v-drag
    ref="dialog"
    :style="{ left: data.left + 'px' }"
    >
    <div class="f-dialog-header drag-target">
    <slot name="header">
    <span>{{ title }}</span>
    </slot>
    <f-icon
    icon="icon-close"
    class="f-modal-close"
    @click="close(false)"
    ></f-icon>
    </div>
    <div class="f-dialog-content">
    <slot></slot>
    </div>
    <div class="f-dialog-footer">
    <slot name="footer">
    <button @click="close(true)">确定</button>
    <button @click="close(false)">取消</button>
    </slot>
    </div>
    </div>

    效果图


更多干货,以及本文的示例代码, 欢迎关注我的公众号: 青城同学 回复 拖拽代码 获取下载地址

当然也可以扫码

使用TypeScript给Vue 3.0写一个指令实现组件拖拽的更多相关文章

  1. 从0写一个Golang日志处理包

    WHY 日志概述 日志几乎是每个实际的软件项目从开发到最后实际运行过程中都必不可少的东西.它对于查看代码运行流程,记录发生的事情等方面都是很重要的. 一个好的日志系统应当能准确地记录需要记录的信息,同 ...

  2. 每天一个JavaScript实例-html5拖拽

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  3. jQuery 学习笔记3 点击弹出一个div并允许拖拽移动

    这里我看了下http://qings.blog.51cto.com/4857138/998878/ 的文章,感谢他的分享. 首先我们有一个a标签和一个div,div默认是不显示的,当用户点击时改为显示 ...

  4. 用extjs6.0写一个点击新建窗口的功能

    一.写一个按钮 注意id { id: 'ListEdit', text:'编辑', iconCls:'x-fa fa-edit' } 二.写新建的页面 下面我新建的是表单,有几点需要注意的: ① 因为 ...

  5. Extjs6(二)——用extjs6.0写一个系统登录及注销

    本文基于ext-6.0.0 一.写login页 1.在view文件夹中创建login文件夹,在login中创建文件login.js和loginController.js(login.js放在class ...

  6. 基于vue框架手写一个notify插件,实现通知功能

    简单编写一个vue插件,当点击时触发notify插件,dom中出现相应内容并且在相应时间之后清除,我们可以在根组件中设定通知内容和延迟消失时间. 1. 基础知识 我们首先初始化一个vue项目,删除不需 ...

  7. Vue.2.0.5-自定义指令

    简介 除了默认设置的核心指令( v-model 和 v-show ),Vue 也允许注册自定义指令.注意,在 Vue2.0 里面,代码复用的主要形式和抽象是组件--然而,有的情况下,你仍然需要对纯 D ...

  8. 如何写一个自己的组件库,打成NPM包,并上传到NPM远程

    1.首先使用vue create my_project 构建一个自己的Vue项目 2.vue.config.js和package.json配置如下,做了些修改 const path = require ...

  9. vue 基础-->进阶 教程(2): 指令、组件

    第二章 建议学习时间4小时  课程共3章 前面的nodejs教程并没有停止更新,因为node项目需要用vue来实现界面部分,所以先插入一个vue教程,以免不会的同学不能很好的完成项目. 本教程,将从零 ...

随机推荐

  1. JVM的整体结构

    整个jvm的运行流程图如上所示,首先需要进行加载class文件,然后使用类加载子系统将class翻译解析导入内存,在内存中分别导入到对应的运行时数据区,然后执行引擎开始执行,对于需要的数据在对应的区域 ...

  2. 如何使用 C# 中的 ValueTask

    在 C# 中利用 ValueTask 避免从异步方法返回 Task 对象时分配 翻译自 Joydip Kanjilal 2020年7月6日 的文章 <How to use ValueTask i ...

  3. [HarekazeCTF2019]Avatar Uploader 1 &&

    [HarekazeCTF2019]Avatar Uploader 1 这是一个文件上传的题目,但是这导体是通过满足条件来获取flag的. 他有两个函数,一个是getimagesize,还有一个是FIL ...

  4. 目标检测:SSD算法详解

    一些概念   True    Predict  True postive False postive  预测为正类 False negivate True negivate  预测为负类    真实为 ...

  5. mac电脑,charles,安卓手机如何配置代理,以及配置代理之后无法上网。已解决

    设备: 电脑:mac book pro 手机:小米10 charles:4.5.6 方法一: 步骤: 首先确保电脑,手机在同一局域网, 1. charles设置代理:proxy -> proxy ...

  6. MySQL表关系总结

    一对多关系  : 一对多关系是关系数据库中两个表之间的一种关系,该关系中第一个表中的单个行可以与第二个表中的一个或多个行相关,但第二个表中的一个行只可以与第一个表中的一个行相关. 一对多关系,一般是一 ...

  7. Linux系统编程 —互斥量mutex

    互斥量mutex 前文提到,系统中如果存在资源共享,线程间存在竞争,并且没有合理的同步机制的话,会出现数据混乱的现象.为了实现同步机制,Linux中提供了多种方式,其中一种方式为互斥锁mutex(也称 ...

  8. mongodb安装教程(亲测有效)

    网上太多教程了,都是说的不明不白,所以自己整理一份 #参考官网: https://docs.mongodb.com/manual/tutorial/install-mongodb-on-red-hat ...

  9. 你在开发过程中使用Git Rebase还是Git Merge?

    摘要:在git里面经常的一个争论是到底用rebase还是用merge? 1. 痛苦吗?代码历史中的迷失羔羊 我们先来看一个真实的代码提交历史图形化截图: 图片源自 https://storage.kr ...

  10. Centos-bzip2压缩文件-bzip2 bunzip2

    bzip2 buzip2 对文件进行压缩与解压缩,类似 gzip gunzip命令,只能压缩文件,对目录则压缩目录下文件,生成以 .bz2为扩展名的文件 相关选项 -d 解压 -v 压缩或解压显示详细 ...