Bootstrap

在el-dialog基础上,封装dialog可最大化,还原,拖动,调整大小

最近,工作上需要,在el-dialog基础上封装了一个可最大化,还原,拖动,调整dialog大小的功能,本来妹子只想简单的用用别人分享出来的代码的,无奈有很多BUG,比如没做移动范围限制,导致能移动到可视窗口外导致无法关闭;调整大小时会出现宽度,高度超过可视区域而引起样式问题,以及滚动条会让可拖动区域失效等问题;然后跟我本来的最大化跟还原功能有部分冲突,导致dialog有很多其他问题。所以妹子只好自己写了(泪目),该代码还是参考了网上别人的部分代码,具体是参考的哪个不记得了(原谅妹子记性不好。。。),如果是用的哪位兄弟的,可以私信我,谢谢。

大概思路就是,单独封装了一个max-dialog的组件,增加了自定义指令v-dialogDrag,然后注册指令,具体注册指令的代码,可以去看官网。

本人项目下其他页面的代码如下:
components/max-dialog/index.vue

<!-- 
@author: debbie.wong;
@email:[email protected]
 -->
<template>
  <el-dialog ref="maxDialog" custom-class="dialogHeightFull maxDialog" :title="title" :fullscreen="fullFlag"
    :visible.sync="maxdialogVisible" :append-to-body="true" :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
      },
      titleVisible: {
        type: Boolean,
        default: true
      },
      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){
          this.$emit('update:dialogVisible', false)
        }
      }
    },
    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('update:dialogVisible', false)
        // 传过来的关闭钩子函数
        this.$emit('closeFun')
      }
    },

    created() {
      this.full = this.isfullscreen
    },
  }
</script>

<style scoped="scoped">
  >>>.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;
  }

  .maxDialog .maxDialog-icon i:hover {
    background-color: #ddd;
  }

  .maxDialog .maxDialog-icon i::before {
    font-size: 80%;
  }

  >>>.maxDialog.dialogHeightFull.el-dialog {
    margin-bottom: 0;
    overflow-y: hidden;
  }

  .el-dialog__wrapper{
    overflow: hidden!important;
  }
  .resize{
    position: absolute;
    right: 0;
    bottom: 0;
    content: '';
    width: 10px;
    height: 10px;
    cursor: se-resize;
  }
</style>

src/directive/dialog.js

/**
@author: debbie.wong;
@email:[email protected]
*/
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')

希望对某些小伙伴有帮助,有问题可以评论,谢谢。

;