更新时间:2022-04-19 09:05:29
1先看看拖拽效言 、
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 对话框
对话框结构
简单的说,一个 div 里面放了三个 div,通过 margin(top、left) 来实现“居中”的效果。那么也就是说我们想要实现拖拽功能的话,可以通过改变 margin-left、margin-top 的方式来。
4
鼠标的三个函数
提到拖拽功能,那么鼠标的三个事件 onmousedown、onmousemove、onmouseup 就必不可少了。
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,这样就和我们拖拽后的 top 不一致。
所以在按下鼠标的时候需要做一个判断。如果恢复了初始状态,那么需要改一下 domset 的 y 坐标。x坐标不用改,因为过渡动画没有改 left 。
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
声明:本文为 脚本之家专栏作者 投稿,未经允许请勿转载。