首页 > 其他 > 详细

使用 vue3 的自定义指令给 element-plus 的 el-dialog 增加拖拽功能

时间:2021-05-28 09:41:13      阅读:68      评论:0      收藏:0      [点我收藏+]

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

拖拽演示

https://www.zhihu.com/zvideo/1380450791975731200

vue3 的自定义指令 directive

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

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

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

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

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

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

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

分析 element-plus 的 Dialog 对话框

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

技术分享图片

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

鼠标的三个函数

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

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

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

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

实现代码

本来想写一个通用一点的,但是对话框渲染出来的结构比较复杂,似乎也不够通用,所以先针对 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 表示结束拖拽。

做成插件便于复用

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

建立一个js文件

//?dialogDrag.js

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

export?default?dialogDrag

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

//?拖拽
import?dialogDrag?from?‘./control-web/js/dialogDrag.js‘

createApp(App).use(dialogDrag)?//?对话框的拖拽
使用方式

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

略...

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

使用 vue3 的自定义指令给 element-plus 的 el-dialog 增加拖拽功能

原文:https://blog.51cto.com/u_15179455/2824096

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!