利用 vue3 给 element-plus 的 el-dialog 增加拖拽功能

前言

代码来自使用 vue3 的自定义指令给 element-plus 的 el-dialog 增加拖拽功能,用的时候发现一些问题,我进行了二次修改。

变化

  • 限制边缘
  • 全屏效果
  • 限制在弹窗的 header 拖动
  • 增加用户体验🤣

效果

部分效果

使用

  1. 新建一个 js 文件,内容为如下代码
  2. main.js 中引入并 use
    // ......
    import dialogDrag from './assets/js/dialogDrag.js'
    var app = createApp(App)
    app.use(dialogDrag)
    // ......
    
  3. 使用的时候 el-dialog 标签用一个 div 包起来,div 加上 v-dialogdrag
    <div v-dialogdrag>
    	<el-dialog v-model="show" :title="title">
    		内容
    	</el-dialog>
    </div>
    

代码

const bus = require("vue3-eventbus")
const dialogDrag = (app) => {
	app.directive('dialogdrag', {
		// 渲染完毕
		mounted(el) {
			// 可视窗口的宽度
			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
			// 超出部分隐藏,不显示滚动条
			el.firstElementChild.style.overflow = "hidden"
			// 重新设置上、左距离
			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
			}
			// 限制拖动弹窗的 header 才可以移动弹窗
			const dialogHeader = el.getElementsByClassName('el-dialog__header')[0]
			
			// 添加右上角全屏显示按钮, i 标签是阿里图标库里面的
			let div = document.createElement('div')
			div.style.fontSize='.8rem'
			div.style.position='absolute'
			div.style.right='45px'
			div.style.top='20px'
			let full_button = document.createElement('span')
			full_button.style.cursor='pointer'
			full_button.innerHTML='<i class="iconfont icon-full"></i>'
			full_button.addEventListener('click', full_dia) // 单击全屏
			div.appendChild(full_button)
			dialogHeader.appendChild(div)
			
			let full = false
			/**
			* 双击全屏
			*/
			dialogHeader.addEventListener('dblclick',full_dia)
			function full_dia(){
				if (full) {
					domset = {
						x: clientWidth / 4,
						y: clientHeight * 15 / 100
					}
					domDrag.style.width = "50%"
					domDrag.style.height = "auto"
					domDrag.style.marginLeft = domset.x + 'px'
					domDrag.style.marginTop = domset.y + 'px'
					full_button.innerHTML='<i class="iconfont icon-full"></i>'
					// 由于我弹窗里面有 echarts 图表,要让图表修改大小,使用的是vue3 bus
					bus.bus.off('domResize')
					bus.bus.emit('domResize', {
						width: domDrag.clientWidth,
						height: domDrag.clientHeight
					})
					full = false
				} else {
					domDrag.style.width = "100%"
					domDrag.style.height = "100%"
					domDrag.style.marginLeft = '0'
					domDrag.style.marginTop = '0'
					full_button.innerHTML='<i class="iconfont icon-fullscreen-exit"></i>'
					bus.bus.off('domResize')
					bus.bus.emit('domResize', {
						width: domDrag.clientWidth,
						height: domDrag.clientHeight
					})
					full = true
				}
			}

			/**
			* 鼠标按下,开始拖拽,添加 mousemove、mouseup 事件
			*/
			dialogHeader.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' // 改变光标形状
				// 鼠标拖出浏览器外部的时候会选中文本,需要禁用
				document.body.style.userSelect = 'none'
				// 使用 document 的 mousemove ,这样鼠标脱离 header 区域还是可以正常拖动(贴着窗口边缘移动)
				// 鼠标移动,实时跟踪
				document.addEventListener('mousemove', dia_mousemove)
				// 鼠标抬起,结束拖拽,once: 只执行一次
				document.addEventListener('mouseup', dia_mouseup, {
					once: true
				})
			}

			/**
			* 鼠标移动,实时跟踪
			*/
			function dia_mousemove(e) {
				if (start.x === 0) { // 不是拖拽状态
					return
				}
				move.x = e.clientX - start.x
				move.y = e.clientY - start.y
				// 弹窗 左、上、右、下 到窗口边缘的距离
				let left = domset.x + move.x,
					top = domset.y + move.y
				let right = left + domDrag.clientWidth,
					bottom = top + domDrag.clientHeight
					
				if (left <= 0) {
					domDrag.style.marginLeft = '0px'
				} else if (right >= clientWidth) {
					domDrag.style.marginLeft = (clientWidth - domDrag.clientWidth) + 'px'
				} else {
					domDrag.style.marginLeft = left + 'px'
				}
				if (top <= 0) {
					domDrag.style.marginTop = '0px'
				} else if (bottom >= clientHeight) {
					domDrag.style.marginTop = (clientHeight - domDrag.clientHeight) + 'px'
				} else {
					domDrag.style.marginTop = top + 'px'
				}
			}

			/**
			* 鼠标抬起,结束拖拽,移除 mousemove 事件
			*/
			function dia_mouseup(e) {
				move.x = e.clientX - start.x
				move.y = e.clientY - start.y
				let left = domset.x + move.x,
					top = domset.y + move.y
				let right = left + domDrag.clientWidth,
					bottom = top + domDrag.clientHeight
					
				domDrag.style.cursor = '' // 恢复光标形状
				document.body.style.userSelect = 'text' // 恢复body可选中
				// 结束拖拽
				start.x = 0
				if (left <= 0) {
					domDrag.style.marginLeft = '0px'
					domset.x = 0
				} else if (right >= clientWidth) {
					domDrag.style.marginLeft = (clientWidth - domDrag.clientWidth) + 'px'
					domset.x = clientWidth - domDrag.clientWidth
				} else {
					domDrag.style.marginLeft = left + 'px'
					domset.x = left
				}
				if (top <= 0) {
					domDrag.style.marginTop = '0px'
					domset.y = 0
				} else if (bottom >= clientHeight) {
					domDrag.style.marginTop = (clientHeight - domDrag.clientHeight) + 'px'
					domset.y = clientHeight - domDrag.clientHeight
				} else {
					domDrag.style.marginTop = top + 'px'
					domset.y = top
				}
				// 结束拖拽
				document.removeEventListener('mousemove', dia_mousemove)
			}
		}
	})
}
export default dialogDrag

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
要在Vue中使用element-ui的el-dialog对话框并实现拖动功能,可以使用vue-draggable-resizable插件来实现。 1. 安装插件 使用npm或者yarn进行安装。 ``` npm install vue-draggable-resizable --save ``` 或者 ``` yarn add vue-draggable-resizable ``` 2. 引入插件 在Vue组件中引入vue-draggable-resizable插件,并注册为全局组件。 ```javascript import Vue from 'vue' import VueDraggableResizable from 'vue-draggable-resizable' import 'vue-draggable-resizable/dist/VueDraggableResizable.css' Vue.component('vue-draggable-resizable', VueDraggableResizable) ``` 3. 使用插件 在el-dialog组件中嵌套vue-draggable-resizable组件,并设置对话框的宽度和高度。 ```html <template> <div> <el-button type="primary" @click="dialogVisible = true">打开对话框</el-button> <el-dialog title="提示" :visible.sync="dialogVisible" width="30%" :before-close="handleClose"> <vue-draggable-resizable :w="dialogWidth" :h="dialogHeight"> <p>这是一个可以拖动的对话框</p> </vue-draggable-resizable> </el-dialog> </div> </template> <script> export default { data() { return { dialogVisible: false, dialogWidth: 400, dialogHeight: 300 } }, methods: { handleClose(done) { this.dialogVisible = false done() } } } </script> ``` 在这个示例中,我们将vue-draggable-resizable组件嵌套在el-dialog组件中,并设置了对话框的宽度和高度。我们还定义了一个handleClose方法来处理对话框关闭的事件。 现在你可以在Vue中使用element-ui的el-dialog对话框并实现拖动功能了。注意:vue-draggable-resizable插件的样式可能需要根据自己的需求进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ByXian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值