Element UI Dialog 可拖拽移动

新建文件 directives.js

import Vue from 'vue';
   
// v-dialogDrag: 弹窗拖拽属性
Vue.directive('dialogDrag', {
    bind(el, binding, vnode, oldVnode) {
        const dialogHeaderEl = el.querySelector('.el-dialog__header');
        const dragDom = el.querySelector('.el-dialog');
        //dialogHeaderEl.style.cursor = 'move';
        dialogHeaderEl.style.cssText += ';cursor:move;'
        dragDom.style.cssText += ';top:0px;'
     
        // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
        const sty = (function() {
            if (window.document.currentStyle) {
                return (dom, attr) => dom.currentStyle[attr];
            } else{
                return (dom, attr) => getComputedStyle(dom, false)[attr];
            }
        })()   
         
        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 = sty(dragDom, 'left');
            let styT = sty(dragDom, 'top');
         
            // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
            if(styL.includes('%')) {
                styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100);
                styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100);
            }else {
                styL = +styL.replace(/\px/g, '');
                styT = +styT.replace(/\px/g, '');
            };
             
            document.onmousemove = function (e) {
                // 通过事件委托,计算移动的距离
                let left = e.clientX - disX;
                let top = e.clientY - disY;
                 
                // 边界处理
                if (-(left) > minDragDomLeft) {
                    left = -(minDragDomLeft);
                } else if (left > maxDragDomLeft) {
                    left = maxDragDomLeft;
                }
                 
                if (-(top) > minDragDomTop) {
                    top = -(minDragDomTop);
                } else if (top > maxDragDomTop) {
                    top = maxDragDomTop;
                }
         
                // 移动当前元素
                dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
            };
         
            document.onmouseup = function (e) {
                document.onmousemove = null;
                document.onmouseup = null;
            };
        }
    }
})

main.js中引入

import ‘./utils/directives’

在el-dialog标签中加入v-dialogDrag属性

属性 close-on-click-modal 取消自动关闭
属性 modal:关闭遮罩
属性 class:注意class添加,overflow hidden否则有溢出

二开el-dialog可最大化,还原,拖动,调整大小

新建 @/components/max-dialog/index.vue

<!--
 * @Author: Yorlg
 * @Email: [email protected]
 * @Date: 2023-01-03
 * @Description: 二次封装el-dialog可最大化,还原,拖动,调整大小
-->
<template>
  <el-dialog
    ref="maxDialog"
    custom-class="dialogHeightFull maxDialog"
    :title="title"
    :fullscreen="fullFlag"
    :visible.sync="maxdialogVisible"
    :modal="false"
    :append-to-body="false"
    :close-on-click-modal="false"
    :show-close="false"
    :width="width"
    :top="top"
    v-if="maxdialogVisible"
    @closed="closeMaxDialog"
    v-dialogDrag
  >
    <div slot="title" class="maxDialog-header">
      <div class="maxDialog-title">
        <span>{{ title }}</span>
      </div>
      <div class="maxDialog-icon">
        <i
          :class="fullFlag ? 'el-icon-copy-document' : 'el-icon-full-screen'"
          @click="IsFullscreen"
        ></i>
        <i class="el-icon-close" @click="closeMaxDialog"></i>
      </div>
    </div>
    <slot name="content" :style="{ height: height }"></slot>
    <div class="resize"></div>
  </el-dialog>
</template>
 
<script>
export default {
  name: 'maxDialog',
  props: {
    dialogVisible: {
      type: Boolean,
      default: false
    },
    width: {
      type: String,
      default: '1200px'
    },
    height: {
      type: String,
      default: '100%'
    },
    top: {
      type: String,
      default: '30px'
    },
    title: {
      type: String,
      default: ''
    },
    isfullscreen: {
      type: Boolean,
      default: false // 默认全屏
    }
  },
  data () {
    return {
      full: false, // 全屏
    }
  },
  computed: {
    fullFlag: {
      get: function () {
        return this.full ?? this.isfullscreen;
      },
      set: function (n) {
        return this.full
      }
    },
    maxdialogVisible: { //重新设置一个变量,接收父级传递的参数
      get: function () {
        return this.dialogVisible
      },
      set: function (value) { }
    }
  },
  mounted () {
  },
  methods: {
    // 全屏 切换
    IsFullscreen () {
      let dialogDom = document.querySelector(".maxDialog");
      if (this.isfullscreen == true) {
        this.full = this.full === null ? false : !this.full
      } else {
        this.full = this.full === null ? true : !this.full
        dialogDom.style.top = `0px`;
        dialogDom.style.left = `auto`;
      }
      // 传过来的全屏钩子函数
      this.$emit('maxFun')
    },
    // 关闭
    closeMaxDialog () {
      this.full = null
      // 传过来的关闭钩子函数
      this.$emit('closeDialog', 'childclose')
    }
  },
 
  created () {
    this.full = this.isfullscreen
  },
}
</script>
 
<style lang="scss" scoped>
::v-deep .el-dialog__header {
  background-color: #f2f2f2;
  /* height: 48px; */
  padding: 10px 20px 10px;
}
 
.maxDialog-header {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}
 
.maxDialog .maxDialog-icon i {
  display: inline-block;
  height: 28px;
  width: 28px;
  line-height: 24px;
  text-align: center;
  border-radius: 50%;
  cursor: pointer;
  font-size: 22px;
}
 
::v-deep .maxDialog.dialogHeightFull.el-dialog {
  margin-bottom: 0;
  overflow-y: hidden;
  margin: none;
  pointer-events: auto;
}
 
.el-dialog__wrapper {
  overflow: hidden !important;
  z-index: 0 !important;
  pointer-events: none;
}
 
.maxDialog .maxDialog-icon i:hover {
  background-color: #ddd;
}
 
.maxDialog .maxDialog-icon i::before {
  font-size: 80%;
}
 
.resize {
  position: absolute;
  right: 0;
  bottom: 0;
  content: "";
  width: 10px;
  height: 10px;
  cursor: se-resize;
}
</style>

新建 @/utils/directives.js

/**
 * @Author: Yorlg
 * @Email: [email protected]
 * @Date: 2023-01-03
 * @Description: 二次封装el-dialog可最大化,还原,拖动,调整大小
*/
import Vue from 'vue'
Vue.directive("dialogDrag", {
  bind (el, binding, vnode, oldVnode) {
    const windowW = document.body.clientWidth;
    const windowH = document.body.clientHeight
    //设置弹框可拉伸最小宽高
    let minWidth = 400;
    let minHeight = 300;
    const dialogHeaderEl = el.querySelector(".el-dialog__header");
    //弹窗
    const dragDom = el.querySelector(".el-dialog");
    //头部加上可拖动cursor
    dialogHeaderEl.style.cursor = "move";
 
    // 获取style属性
    const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null);
 
    let moveDown = e => {
      // 鼠标按下,计算当前元素距离可视区的距离
      const disX = e.clientX - dialogHeaderEl.offsetLeft;
      const disY = e.clientY - dialogHeaderEl.offsetTop;
 
      // 获取到的值带px 正则匹配替换
      let styL, styT, styMT;
      // 注意在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, "");
        styMT = +sty.marginTop.replace(/\px/g, "")
      }
 
      document.onmousemove = function (e) {
        const titleH = dialogHeaderEl.offsetHeight;
 
        // 通过事件委托,计算移动的距离
        let l = e.clientX - disX;
        let t = e.clientY - disY;
 
        // 移动边界处理
        if (t < 0 && (t + styMT + styT) <= 0 || t < 0 && (styMT + styT) <= 0) {
          t = -(styMT + styT);
        } else if (t > 0 && t > (document.body.clientHeight - styMT - styT - titleH)) {
          t = document.body.clientHeight - styMT - styT - titleH;
        }
 
        // 移动当前元素
        dragDom.style.left = `${l + styL}px`;
        dragDom.style.top = `${t + styT}px`;
 
      };
 
      document.onmouseup = function (e) {
        document.onmousemove = null;
        document.onmouseup = null;
      };
 
    };
 
    dialogHeaderEl.onmousedown = moveDown;
 
    dragDom.onmousemove = function (e) {
      const dialogBODY = el.querySelector(".el-dialog__body");
      const resizeDom = el.querySelector(".resize");
      const titleH = dialogHeaderEl.offsetHeight;
      dragDom.onmousedown = e => {
        const clientX = e.clientX;
        const clientY = e.clientY;
        let elW = dragDom.clientWidth;
        let elH = dragDom.clientHeight;
        let EloffsetLeft = dragDom.offsetLeft;
        let EloffsetTop = dragDom.offsetTop;
        dragDom.style.userSelect = "none";
        let ELscrollTop = el.scrollTop;
        let resizeW = resizeDom.clientWidth, resizeH = resizeDom.clientHeight;
 
        //判断点击的位置是不是为头部
        if (
          clientX > EloffsetLeft &&
          clientX < EloffsetLeft + elW &&
          clientY > EloffsetTop &&
          clientY < EloffsetTop + 100
        ) {
          //如果是头部
        } else {
          document.onmousemove = function (e) {
            e.preventDefault(); // 移动时禁用默认事件
            //鼠标拖拽
            if (
              clientX > EloffsetLeft + elW - resizeW &&
              clientX < EloffsetLeft + elW
            ) {
              //往左拖拽
              if (clientX > e.clientX) {
                if (dragDom.clientWidth < minWidth) {
                } else {
                  dragDom.style.width = elW - (clientX - e.clientX) * 2 + "px";
                }
              }
              //往右拖拽
              if (clientX <= e.clientX) {
                let targetTW = elW + (e.clientX - clientX) * 2
                targetTW > windowW ?
                  dragDom.style.width = windowW + "px" :
                  dragDom.style.width = targetTW + "px"
              }
            }
            //底部鼠标拖拽位置
            if (
              ELscrollTop + clientY > EloffsetTop + elH - resizeH &&
              ELscrollTop + clientY < EloffsetTop + elH
            ) {
              //往上拖拽
              if (clientY > e.clientY) {
                if (dragDom.clientHeight < minHeight) {
                } else {
                  dragDom.style.height = elH - (clientY - e.clientY) * 1 + "px";
                  dialogBODY.style.height = elH - (clientY - e.clientY) * 1 - titleH + "px";
                }
              }
              //往下拖拽
              if (clientY <= e.clientY) {
                e.clientY >= windowH ?
                  dragDom.style.height = windowH - dragDom.offsetTop + "px" :
                  dragDom.style.height = elH + (e.clientY - clientY) * 1 + "px";
                dialogBODY.style.height = elH - (clientY - e.clientY) * 1 - titleH + "px";
              }
            }
          };
          //结束
          document.onmouseup = function (e) {
            document.onmousemove = null;
            document.onmouseup = null;
          };
        }
      };
    };
  }
});
export default Vue.directive('dialogDrag')
 
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
下一篇