使用TypeScript给Vue 3.0写一个指令实现组件拖拽

简介: 使用TypeScript给Vue 3.0写一个指令实现组件拖拽

最近在用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;
  1. 如何限制拖动的节点只能在屏幕内移动,不能移动出屏幕呢?
  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;
}
  1. 限制left不能大于可视区域的宽度减去当前html节点的宽度,如果left大于这个宽度,那么当前html节点肯定右侧已经处于显示区域的右侧外边了
if (left > bodyW - el.offsetWidth) {
    left = bodyW - el.offsetWidth;
}
  1. 上下拖拽位置限制和左右拖拽限制思路是一样,只要保证top的值大于0且小于屏幕可视范围的高度减去当前html节点的高度,那么拖动就无法拖出屏幕了。
let top = elTop - (y - move.clientY);
if (top < 0) {
      top = 0;
}
if (top > bodyH - el.offsetHeight) {
      top = bodyH - el.offsetHeight
}
  1. 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;
            }
        })
    }
}
  1. 使用
import DragDirective from './DragDirective'
createApp(App).use(DragDirective).mount('#app')
  1. 注册指令到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>
  1. 效果图
目录
相关文章
|
3天前
|
JavaScript
Vue中如何实现兄弟组件之间的通信
在Vue中,兄弟组件可通过父组件中转、事件总线、Vuex/Pinia或provide/inject实现通信。小型项目推荐父组件中转或事件总线,大型项目建议使用Pinia等状态管理工具,确保数据流清晰可控,避免内存泄漏。
47 1
|
3月前
|
人工智能 JavaScript 算法
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
515 0
|
3月前
|
JavaScript UED
用组件懒加载优化Vue应用性能
用组件懒加载优化Vue应用性能
|
5月前
|
JavaScript
vue实现任务周期cron表达式选择组件
vue实现任务周期cron表达式选择组件
721 4
|
4月前
|
JavaScript 数据可视化 前端开发
基于 Vue 与 D3 的可拖拽拓扑图技术方案及应用案例解析
本文介绍了基于Vue和D3实现可拖拽拓扑图的技术方案与应用实例。通过Vue构建用户界面和交互逻辑,结合D3强大的数据可视化能力,实现了力导向布局、节点拖拽、交互事件等功能。文章详细讲解了数据模型设计、拖拽功能实现、组件封装及高级扩展(如节点类型定制、连接样式优化等),并提供了性能优化方案以应对大数据量场景。最终,展示了基础网络拓扑、实时更新拓扑等应用实例,为开发者提供了一套完整的实现思路和实践经验。
523 77
|
3月前
|
自然语言处理 JavaScript 前端开发
一夜获千星!已获 1.7k+,Art Design Pro:Vue3 + Vite + TypeScript 打造的高颜值管理系统模板,这个让后端小哥直呼救命的后台系统
Art Design Pro 是一款基于 Vue 3、Vite 和 TypeScript 的高颜值后台管理系统模板,已获 1.7k+ 星标。项目专注于用户体验与视觉设计,支持主题切换、多语言、权限管理及图表展示等功能,内置常用业务组件,便于快速搭建现代化管理界面。其技术栈先进,开发体验流畅,适配多设备,满足企业级应用需求。项目地址:[GitHub](https://github.com/Daymychen/art-design-pro)。
515 11
|
3月前
|
JavaScript 前端开发 UED
Vue 表情包输入组件的实现代码:支持自定义表情库、快捷键发送和输入框联动的聊天表情解决方案
本文详细介绍了在 Vue 项目中实现一个功能完善、交互友好的表情包输入组件的方法,并提供了具体的应用实例。组件设计包含表情分类展示、响应式布局、与输入框的交互及样式定制等功能。通过核心技术实现,如将表情插入输入框光标位置和点击外部关闭选择器,确保用户体验流畅。同时探讨了性能优化策略,如懒加载和虚拟滚动,以及扩展性方案,如自定义主题和国际化支持。最终,展示了如何在聊天界面中集成该组件,为用户提供丰富的表情输入体验。
305 8
|
4月前
|
JavaScript 前端开发 编译器
Vue与TypeScript:如何实现更强大的前端开发
Vue.js 以其简洁的语法和灵活的架构在前端开发中广受欢迎,而 TypeScript 作为一种静态类型语言,为 JavaScript 提供了强大的类型系统和编译时检查。将 Vue.js 与 TypeScript 结合使用,不仅可以提升代码的可维护性和可扩展性,还能减少运行时错误,提高开发效率。本文将介绍如何在 Vue.js 项目中使用 TypeScript,并通过一些代码示例展示其强大功能。
200 22
|
3月前
|
JavaScript 前端开发 UED
Vue 表情包输入组件实现代码及详细开发流程解析
这是一篇关于 Vue 表情包输入组件的使用方法与封装指南的文章。通过安装依赖、全局注册和局部使用,可以快速集成表情包功能到 Vue 项目中。文章还详细介绍了组件的封装实现、高级配置(如自定义表情列表、主题定制、动画效果和懒加载)以及完整集成示例。开发者可根据需求扩展功能,例如 GIF 搜索或自定义表情上传,提升用户体验。资源链接提供进一步学习材料。
191 1
|
3月前
|
JavaScript API 开发者
Vue框架中常见指令的应用概述。
通过以上的详细解析,你应该已经初窥Vue.js的指令的威力了。它们是Vue声明式编程模型的核心之一,无论是构建简单的静态网站还是复杂的单页面应用,你都会经常用到。记住,尽管Vue提供了大量预定义的指令,你还可以创建自定义指令以满足特定的需求。为你的Vue应用程序加上这些功能增强器,让编码变得更轻松、更愉快吧!
67 1