Vue实现打开多个可拖动弹窗
创作时间:
作者:
@小白创作中心
Vue实现打开多个可拖动弹窗
引用
CSDN
1.
https://blog.csdn.net/weixin_46205984/article/details/130405788
实现可拖动这一功能的话网上教程很多,而我需要在此基础上实现点击页面打开多个可拖动弹出框。
首先执行以下命令,安装vuedraggable,通过vuedraggable 实现拖动过渡动画比较好。
npm install vuedraggable --save
新建dialogDrag.js文件,文件内容如下:
import Vue from 'vue'
Vue.directive('dialogDrag', {
bind(el) {
const dialogHeaderEl = el.querySelector('.el-dialog__header')
const dragDom = el.querySelector('.el-dialog')
dialogHeaderEl.style.cursor = 'move'
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null)
dialogHeaderEl.onmousedown = (e) => {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - dialogHeaderEl.offsetLeft
const disY = e.clientY - dialogHeaderEl.offsetTop
const screenWidth = document.body.clientWidth // body当前宽度
const screenHeight = document.documentElement.clientHeight // 可见区域高度(应为body高度,可某些环境下无法获取)
const dragDomWidth = dragDom.offsetWidth // 对话框宽度
const dragDomheight = dragDom.offsetHeight // 对话框高度
const minDragDomLeft = dragDom.offsetLeft
const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth
const minDragDomTop = dragDom.offsetTop
const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight
// 获取到的值带px 正则匹配替换
let styL, styT
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (sty.left.includes('%')) {
styL = +document.body.clientWidth * (+sty.left.replace(/%/g, '') / 100)
styT = +document.body.clientHeight * (+sty.top.replace(/%/g, '') / 100)
} else {
styL = +sty.left.replace(/\px/g, '')
styT = +sty.top.replace(/\px/g, '')
}
document.onmousemove = function(e) {
// 获取body的页面可视宽高
// var clientHeight = document.documentElement.clientHeight || document.body.clientHeight
// var clientWidth = document.documentElement.clientWidth || document.body.clientWidth
// 通过事件委托,计算移动的距离
var l = e.clientX - disX
var t = e.clientY - disY
// 边界处理
if (-l > minDragDomLeft) {
l = -minDragDomLeft
} else if (l > maxDragDomLeft) {
l = maxDragDomLeft
}
if (-t > minDragDomTop) {
t = -minDragDomTop
} else if (t > maxDragDomTop) {
t = maxDragDomTop
}
// 移动当前元素
dragDom.style.left = `${l + styL}px`
dragDom.style.top = `${t + styT}px`
// 将此时的位置传出去
// binding.value({x:e.pageX,y:e.pageY})
}
document.onmouseup = function() {
document.onmousemove = null
document.onmouseup = null
}
}
}
})
在页面中通过v-dialogDrag命令绑定到组件上,实现拖动效果。
<el-dialog
v-dialogDrag //绑定拖动效果
:title="title"
:lock-scroll="false"
:close-on-press-escape="false"
:visible.sync="dialogVisible"
width="30%"
:append-to-body="true" // 解决弹窗关不掉或者在弹窗框上层多出一个遮罩层的问题
destroy-on-close>
<el-image :src="imageUrl"></el-image>
</el-dialog>
此时已实现弹窗框的可拖动效果。但还未达到我的需求,接下来需要实现打开弹出框可以继续操作页面。弹出框默认是有遮罩层的,需要关闭遮罩层,同时关闭通过点击 modal 关闭 Dialog。
<el-dialog
v-dialogDrag //绑定拖动效果
:title="title"
:lock-scroll="false"
:close-on-press-escape="false"
:visible.sync="dialogVisible"
width="30%"
:append-to-body="true" // 解决弹窗关不掉或者在弹窗框上层多出一个遮罩层的问题
:close-on-click-modal="false" //关闭通过点击 modal 关闭 Dialog
:modal="false" // 关闭遮罩层
destroy-on-close>
<el-image :src="imageUrl"></el-image>
</el-dialog>
接下来实现打开弹窗后可继续点击页面。
加上下边css样式即可。
.el-dialog__wrapper {
pointer-events: none;
}
.el-dialog {
pointer-events:auto;
}
注意:css样式一定要写对位置,否则会不生效,因为.el-dialog样式未生效,于是把.el-dialog样式写到了dialogDrag.js文化中。
最终版代码如下:
import Vue from 'vue'
// v-dialogDrag: 弹窗拖拽
Vue.directive('dialogDrag', {
bind(el) {
const dialogHeaderEl = el.querySelector('.el-dialog__header')
const dragDom = el.querySelector('.el-dialog')
dialogHeaderEl.style.cursor = 'move'
// 重点!!!!解决打开多个弹窗后,弹窗失去拖动功能
// .el-dialog样式
dragDom.style.pointerEvents = 'auto';
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null)
dialogHeaderEl.onmousedown = (e) => {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - dialogHeaderEl.offsetLeft
const disY = e.clientY - dialogHeaderEl.offsetTop
const screenWidth = document.body.clientWidth // body当前宽度
const screenHeight = document.documentElement.clientHeight // 可见区域高度(应为body高度,可某些环境下无法获取)
const dragDomWidth = dragDom.offsetWidth // 对话框宽度
const dragDomheight = dragDom.offsetHeight // 对话框高度
const minDragDomLeft = dragDom.offsetLeft
const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth
const minDragDomTop = dragDom.offsetTop
const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight
// 获取到的值带px 正则匹配替换
let styL, styT
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (sty.left.includes('%')) {
styL = +document.body.clientWidth * (+sty.left.replace(/%/g, '') / 100)
styT = +document.body.clientHeight * (+sty.top.replace(/%/g, '') / 100)
} else {
styL = +sty.left.replace(/\px/g, '')
styT = +sty.top.replace(/\px/g, '')
}
document.onmousemove = function(e) {
// 获取body的页面可视宽高
// var clientHeight = document.documentElement.clientHeight || document.body.clientHeight
// var clientWidth = document.documentElement.clientWidth || document.body.clientWidth
// 通过事件委托,计算移动的距离
var l = e.clientX - disX
var t = e.clientY - disY
// 边界处理
if (-l > minDragDomLeft) {
l = -minDragDomLeft
} else if (l > maxDragDomLeft) {
l = maxDragDomLeft
}
if (-t > minDragDomTop) {
t = -minDragDomTop
} else if (t > maxDragDomTop) {
t = maxDragDomTop
}
// 移动当前元素
dragDom.style.left = `${l + styL}px`
dragDom.style.top = `${t + styT}px`
// 将此时的位置传出去
// binding.value({x:e.pageX,y:e.pageY})
}
document.onmouseup = function() {
document.onmousemove = null
document.onmouseup = null
}
}
}
})
<template>
<div class="dd_class_div">
<el-dialog
v-dialogDrag //绑定拖动效果
:title="title"
:lock-scroll="false"
:close-on-press-escape="false"
:visible.sync="dialogVisible"
width="30%"
:append-to-body="true" // 解决弹窗关不掉或者在弹窗框上层多出一个遮罩层的问题
:close-on-click-modal="false" //关闭通过点击 modal 关闭 Dialog
:modal="false" // 关闭遮罩层
destroy-on-close>
<el-image :src="imageUrl"></el-image>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'draggableDialog',
data() {
return {
dialogVisible:false,
imageUrl:'',
title:''
}
},
methods: {
dialogClose(){
this.dialogVisible = false;
}
}
}
</script>
<style scoped>
.el-dialog__wrapper{
pointer-events: none;
}
.dd_class_div {
text-align: center;
}
</style>
热门推荐
装修小白必看!三种主流墙面材料优劣全解析
2024年成都幼儿园入园政策详解
南玉高铁联调联试开通在即:有效助推区域经济发展
甲强龙治疗哮喘的用法、用量是多少
从5届“三大奖”预测第三轮“双一流”!深大广工谁更有戏?
120单反相机的发展历程:从EXAKTA到宾得67
铁路市场化定价:“一元票价”传递民生温度
为何《寒江独钓图》受千年追捧?专家放大20倍、发现“现代科技”
网上配眼镜跟线下配效果差不多,但更加价廉物美?
公考面试习惯讲假大空的话,内容干巴巴的没有事例,怎么办?
登山杖伸缩和折叠哪种最好最实用?登山杖选购指南
必看+收藏!医保政策热点问答,你想知道的都在这里
Intel集成显卡和AMD集成显卡哪个更优秀?性能对比分析
外国留学生:在中国生活得越久,越能发现中国的魅力
百日咳再现,了解这些才能更好地保护孩子
肝癌可以用中药控制病情吗?效果怎么样
新手必读:电脑硬件配置选购完全指南
科技投资新趋势:从放缓到价值创造
小乌龟风水摆件:寓意与摆放位置全解析
以撒与利百加的婚姻:《圣经》中的神圣结合与多面启示
26个实用且天才的省钱法
古代白酒和现代到底有什么区别?
武汉一般玩几天比较好
福建中医药大学实践队探秘客家文化:从祖地寻根到非遗体验
拜仁2024年成绩总结:49场30胜,自10-11赛季以来首次无冠
季节交替,秋季过敏高发期!该怎么应对?
小型便携式点焊机的点焊操作技巧
车祸中的心理应对:恢复信心的有效方法
素食者必读:容易缺乏的六种关键营养素及补充方法
不移民怎样畅游欧洲国家?实用攻略和建议