使用TypeScript给Vue 3.0写一个指令实现组件拖拽
最近在用vue3重构后台的一个功能。一个弹窗组件,弹出一个表单。然后点击提交。
早上运维突然跑过来问我,为啥弹窗挡住了下边的表格的数据,我添加的时候,都没法对照表格来看了。你必须给我解决一下。
我参考了一下几大Vue的ui组件库。发现element iview antv。好像都没这个功能。为啥运维需要这个功能??
但是没办法,只能整一个就是了。
做之前本来想直接做到dialog这个组件中。但是又担心后面其他的组件会用到。于是决定把拖拽功能做到指令中。
整个功能点如图。鼠标在拖拽区域拖动,整个对话框在浏览器可视范围内移动。
Drag指令主要实现思路
在指令挂载的时候,监听当前html节点的鼠标点击事件
然后在点击当前html节点的时候,判断是否点击在drag-target这个class所在的子节点上。如果是,那么触发document鼠标移动事件。然后计算出鼠标移动距离,对应修改弹出框的left值和top值。并记录下当前按下的位置x和y
let x = e.clientX;
let y = e.clientY;
如何限制拖动的节点只能在屏幕内移动,不能移动出屏幕呢?
限制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;
}
限制left不能大于可视区域的宽度减去当前html节点的宽度,如果left大于这个宽度,那么当前html节点肯定右侧已经处于显示区域的右侧外边了
if (left > bodyW - el.offsetWidth) {
left = bodyW - el.offsetWidth;
}
上下拖拽位置限制和左右拖拽限制思路是一样,只要保证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写一个指令实现组件拖拽的更多相关文章
- 从0写一个Golang日志处理包
WHY 日志概述 日志几乎是每个实际的软件项目从开发到最后实际运行过程中都必不可少的东西.它对于查看代码运行流程,记录发生的事情等方面都是很重要的. 一个好的日志系统应当能准确地记录需要记录的信息,同 ...
- 每天一个JavaScript实例-html5拖拽
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- jQuery 学习笔记3 点击弹出一个div并允许拖拽移动
这里我看了下http://qings.blog.51cto.com/4857138/998878/ 的文章,感谢他的分享. 首先我们有一个a标签和一个div,div默认是不显示的,当用户点击时改为显示 ...
- 用extjs6.0写一个点击新建窗口的功能
一.写一个按钮 注意id { id: 'ListEdit', text:'编辑', iconCls:'x-fa fa-edit' } 二.写新建的页面 下面我新建的是表单,有几点需要注意的: ① 因为 ...
- Extjs6(二)——用extjs6.0写一个系统登录及注销
本文基于ext-6.0.0 一.写login页 1.在view文件夹中创建login文件夹,在login中创建文件login.js和loginController.js(login.js放在class ...
- 基于vue框架手写一个notify插件,实现通知功能
简单编写一个vue插件,当点击时触发notify插件,dom中出现相应内容并且在相应时间之后清除,我们可以在根组件中设定通知内容和延迟消失时间. 1. 基础知识 我们首先初始化一个vue项目,删除不需 ...
- Vue.2.0.5-自定义指令
简介 除了默认设置的核心指令( v-model 和 v-show ),Vue 也允许注册自定义指令.注意,在 Vue2.0 里面,代码复用的主要形式和抽象是组件--然而,有的情况下,你仍然需要对纯 D ...
- 如何写一个自己的组件库,打成NPM包,并上传到NPM远程
1.首先使用vue create my_project 构建一个自己的Vue项目 2.vue.config.js和package.json配置如下,做了些修改 const path = require ...
- vue 基础-->进阶 教程(2): 指令、组件
第二章 建议学习时间4小时 课程共3章 前面的nodejs教程并没有停止更新,因为node项目需要用vue来实现界面部分,所以先插入一个vue教程,以免不会的同学不能很好的完成项目. 本教程,将从零 ...
随机推荐
- 跟我一起学.NetCore之路由的最佳实现
前言 路由,这词绝对不陌生,不管在前端还是后端都经常提到,而这节不说其他,就聊.NetCore的路由:在之前的Asp.Net MVC 中,路由算是面试时必问的考点,可见其重要性,它的主要作用是映射UR ...
- SSTI服务器模板注入(以及关于渲染,solt的学习)&&[BJDCTF2020]The mystery of ip 1
ssti服务器模板注入 ssti:利用公共 Web 框架的服务器端模板作为攻击媒介的攻击方式,该攻击利用了嵌入模板的用户输入方式的弱点.SSTI 攻击可以用来找出 Web 应用程序的内容结构. slo ...
- 图形渲染的大致过程和关于OpenGL渲染管线的一些零碎知识,openglpipeline,vao,vbo,ebo.
重要!!! OpenGL新人一枚,希望可以再此和大家分享有用的知识,少走弯路 文章会定期更新,把前面几段已经整理过的知识更完后,接下来每周至少会更两次. 文章如果有不对的,理解错误的地方,也非常希望在 ...
- 手把手教你在 TKE 集群中实现简单的蓝绿发布和灰度发布
概述 如何在腾讯云 Kubernetes 集群实现蓝绿发布和灰度发布?通常要向集群额外部署其它开源工具来实现,比如 Nginx Ingress,Traefik 等,或者让业务上 Service Mes ...
- java实现点击查询数据生成excel文件并下载
须先导入关键maven包 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi& ...
- Vue中computed分析
Vue中computed分析 在Vue中computed是计算属性,其会根据所依赖的数据动态显示新的计算结果,虽然使用{{}}模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的,在模板中放入太 ...
- 中秋礼物!开源即时通信GGTalk安卓版全新源码!
经过连续两个多月的努力(开发.调试.测试.改bug),我们终于赶在中秋国庆之前能把全新的GGTalk Android版本献给大家. 4年之前我们就推出了GGTalk Android的第一个版本,但是功 ...
- UltraEdit文字编辑器菜单热键推荐
键盘映射和自定义菜单热键 任何使用过UltraEdit / UEStudio一段时间的人都可能会告诉您,他们如此喜欢它的原因之一是"几乎所有东西都是可定制的".看一下产品鉴定,您会 ...
- 中心极限定理(为什么y服从高斯分布)
因为每一条数据都服从IID原则: 根据中心极限定理,当数据增加的时候,样本均值的分布慢慢变成正态分布 不管分布式什么分布,累加起来都是高斯分布 As sum increases, sum of non ...
- JVM 内存分配和占用
我们从一个简单示例来引出JVM的内存模型 简单示例 我从一个简单示例谈起这一块,我在看一篇文章的时候看到这么一个场景并且自己做了尝试,就是分配一个2M的数组,使用Xmx即最大内存为12M的话,会报错J ...