问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

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>

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号