妙!vue自定义指令实现一个可拖拽对话框(el-dialog专用)

简介: element-plus 提供的 el-dialog 对话框功能非常强大,只是美中不足不能通过拖拽的方式改变位置,有点小遗憾,那么怎么办呢?我们可以通过 vue 的自定义指令来实现一个可以拖拽的对话框(el-dialog)。

1先看看拖拽效言   、


72.png

活链接


2

 vue 的自定义指令 directive  

为啥选择自定义指令的方式来实现呢?一个是可以方便的获得 dom 便于操作,另一个是方便使用和封装。

自定义指令有两种注册方式,一个是全局注册,一个是局部注册。

  • 全局注册自定义指令
app.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
mounted(el) {
// Focus the element
el.focus()
}
})

来自于官网。后面做插件的时候需要用到。

  • 局部注册自定义指令
directives: {
focus: {
// 指令的定义
mounted(el) {
el.focus()
}
}
}


在开发测试的阶段可以用这种方式,便于调试。插件每次修改的时候都会重新加载,而局部注册的只需要局部更新即可。

我们可以定义一个 dialogdrag,然后在 mounted 里面实现拖拽的功能。

3

 分析 element-plus 的 Dialog 对话框  

想要实现拖拽功能,首先要了解 Dialog 对话框渲染出来的结构,然后才好针对性下手改造。通过分析可见如下结构:

73.png


对话框结构

简单的说,一个 div 里面放了三个 div,通过 margin(top、left) 来实现“居中”的效果。那么也就是说我们想要实现拖拽功能的话,可以通过改变 margin-left、margin-top 的方式来。

4

 鼠标的三个函数  

提到拖拽功能,那么鼠标的三个事件 onmousedown、onmousemove、onmouseup 就必不可少了。

  • onmousedown
    鼠标按下的时候记录光标的坐标,进入拖拽状态。

  • onmouseup
    鼠标抬起的时候记录光标的坐标,结束拖拽状态。

  • onmousemove
    按住鼠标拖动的时候触发,计算光标的偏移量,修改对话框的 margin 实现拖拽的效果。

5

 实现代码  

本来想写一个通用一点的,但是对话框渲染出来的结构比较复杂,似乎也不够通用,所以先针对 el-dialog 实现拖拽功能。

app.directive('dialogdrag', {
// 渲染完毕
mounted(el, binding) {
// binding.arg
// binding.value
// 可视窗口的宽度
const clientWidth = document.documentElement.clientWidth
// 可视窗口的高度
const clientHeight = document.documentElement.clientHeight
// 记录坐标
let domset = {
x: clientWidth / 4, // 默认width 50%
y: clientHeight * 15 / 100// 根据 15vh 计算
}
// 弹窗的容器
const domDrag = el.firstElementChild.firstElementChild
// 重新设置上、左距离
domDrag.style.marginTop = domset.y + 'px'
domDrag.style.marginLeft = domset.x + 'px'
// 记录拖拽开始的光标坐标,0 表示没有拖拽
let start = { x: 0, y: 0 }
// 移动中记录偏移量
let move = { x: 0, y: 0 }
// 鼠标按下,开始拖拽
domDrag.onmousedown = (e) => {
// 判断对话框是否重新打开
if (domDrag.style.marginTop === '15vh') {
// 重新打开,设置 domset.y top
domset.y = clientHeight * 15 / 100
}
start.x = e.clientX
start.y = e.clientY
domDrag.style.cursor = 'move'// 改变光标形状
}
// 鼠标移动,实时跟踪
domDrag.onmousemove = (e) => {
if (start.x === 0) { // 不是拖拽状态
return
}
move.x = e.clientX - start.x
move.y = e.clientY - start.y
// 初始位置 + 拖拽距离
domDrag.style.marginLeft = ( domset.x + move.x ) + 'px'
domDrag.style.marginTop = ( domset.y + move.y ) + 'px'
}
// 鼠标抬起,结束拖拽
domDrag.onmouseup = (e) => {
move.x = e.clientX - start.x
move.y = e.clientY - start.y
// 记录新坐标,作为下次拖拽的初始位置
domset.x += move.x
domset.y += move.y
domDrag.style.cursor = ''// 恢复光标形状
domDrag.style.marginLeft = domset.x + 'px'
domDrag.style.marginTop = domset.y + 'px'
// 结束拖拽
start.x = 0
}
}
})


  • 重新定位对话框
    默认的 top 是15vh,也就是距离顶部 15% ,所以需要 用 clientHeight * 15 / 100 转换为像素。默认的 left 是 50%,所以需要用 clientWidth / 4 转换为像素。

这样修改有一个小问题,当窗口大小发生改变的时候,左距离不会随之改变。

  • 记录位置坐标和偏移量
    首先要记录对话框的距离,然后要记录拖拽的时候产生的偏移量。
  1. domset 可以记录对话框的初始坐标。
  2. start 可以记录开始拖拽的时候光标的位置。
  3. move 记录拖拽过程中,光标移动的偏移量。
  • 按下鼠标 onmousedown
    按下鼠标,表示开始拖拽,这时候需要我们记录光标的位置。另外在测试的时候发现一个小问题,当关闭对话框的时候有一个过渡动画,然后在打开对话框进行拖拽的时候,就飞掉了。

找了一下原因后发现,在关闭的过渡动画的时候,会把 top 改成 15vh,这样就和我们拖拽后的 top 不一致。

所以在按下鼠标的时候需要做一个判断。如果恢复了初始状态,那么需要改一下 domset 的 y 坐标。x坐标不用改,因为过渡动画没有改 left 。

  • 移动鼠标 onmousemove
    在移动鼠标的过程中,我们可以得到光标的位置,减去初始光标位置,就是对话框要移动的距离。
    然后我们用对话框的 初始坐标 + 偏移量,就可以得到对话框的新的位置坐标。这样就实现了对话框的拖拽。

  • 抬起鼠标 onmouseup 不能一直拖拽,所以我们需要一个结束动作。
    当抬起鼠标的时候,我们可以认为是结束拖拽了,这时我们要记录对话框的新的位置坐标, 然后设置 start.x = 0 表示结束拖拽。

6

 做成插件便于复用  

最后我们把这个拖拽功能做成一个插件,这样可以便于全局注册。

建立一个js文件

// dialogDrag.js
const dialogDrag = (app, options) => {
app.directive('dialogdrag', {
// 指令的定义
mounted(el, binding) {
同上,略...
}
exportdefault dialogDrag

然后在 main.js 里面挂载这个插件。

// 拖拽
import dialogDrag from'./control-web/js/dialogDrag.js'
createApp(App).use(dialogDrag) // 对话框的拖拽

7

 使用方式  

本来想直接放在 el-dialog 里面,但是却没有效果,所以只好在外面套上一个 div。


<div v-dialogdrag>
<el-dialog
title="收货地址"
v-model="dialogFormVisible"
:modal="false"
>
略...
el-dialog>
div>


注意,要加上 v- ,即 v-dialogdrag。

本文作者:自然框架

个人网址:jyk.cnblogs.com

声明:本文为 脚本之家专栏作者 投稿,未经允许请勿转载。

相关文章
|
6天前
|
移动开发 JavaScript API
Vue Router 核心原理
Vue Router 是 Vue.js 的官方路由管理器,用于实现单页面应用(SPA)的路由功能。其核心原理包括路由配置、监听浏览器事件和组件渲染等。通过定义路径与组件的映射关系,Vue Router 将用户访问的路径与对应的组件关联,支持哈希和历史模式监听 URL 变化,确保页面导航时正确渲染组件。
|
10天前
|
监控 JavaScript 前端开发
ry-vue-flowable-xg:震撼来袭!这款基于 Vue 和 Flowable 的企业级工程项目管理项目,你绝不能错过
基于 Vue 和 Flowable 的企业级工程项目管理平台,免费开源且高度定制化。它覆盖投标管理、进度控制、财务核算等全流程需求,提供流程设计、部署、监控和任务管理等功能,适用于企业办公、生产制造、金融服务等多个场景,助力企业提升效率与竞争力。
61 12
|
6天前
|
JavaScript 前端开发 开发者
Vue中的class和style绑定
在 Vue 中,class 和 style 绑定是基于数据驱动视图的强大功能。通过 class 绑定,可以动态更新元素的 class 属性,支持对象和数组语法,适用于普通元素和组件。style 绑定则允许以对象或数组形式动态设置内联样式,Vue 会根据数据变化自动更新 DOM。
|
6天前
|
JavaScript 前端开发 数据安全/隐私保护
Vue Router 简介
Vue Router 是 Vue.js 官方的路由管理库,用于构建单页面应用(SPA)。它将不同页面映射到对应组件,支持嵌套路由、路由参数和导航守卫等功能,简化复杂前端应用的开发。主要特性包括路由映射、嵌套路由、路由参数、导航守卫和路由懒加载,提升性能和开发效率。安装命令:`npm install vue-router`。
|
2月前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
147 1
|
27天前
|
JavaScript 安全 API
iframe嵌入页面实现免登录思路(以vue为例)
通过上述步骤,可以在Vue.js项目中通过 `iframe`实现不同应用间的免登录功能。利用Token传递和消息传递机制,可以确保安全、高效地在主应用和子应用间共享登录状态。这种方法在实际项目中具有广泛的应用前景,能够显著提升用户体验。
54 8
|
28天前
|
存储 设计模式 JavaScript
Vue 组件化开发:构建高质量应用的核心
本文深入探讨了 Vue.js 组件化开发的核心概念与最佳实践。
74 1
|
3月前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
111 58
|
2月前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
3月前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
67 1
vue学习第一章

热门文章

最新文章