VUE自定义弹窗,使用ant-design-vue图片预览功能后,关闭弹窗时为什么会报错?

作者站长头像
站长
· 阅读数 9

我自己写了一个弹窗组件,在一种情况下会报错,但是找不到报错原因。打开弹窗后,在弹窗中使用ant-design-vue的图片预览功能,然后关闭弹窗时会报错。VUE自定义弹窗,使用ant-design-vue图片预览功能后,关闭弹窗时为什么会报错?弹窗代码如下:

<!-- 使用方法
<m-dialog v-model:visible="_d.visible" 
      title="产品信息编辑"
      width="800px"
      :okLoading="_d.loading"
      @ok="onSubmit"
      @closed="() => resetFields()">
</m-dialog>
-->
<template>
<div v-if="_d.show1" ref="mDialogWrapperRef"
    class="m-dialog-wrapper" 
    :class="{
        show: _d.show3,
        'is-drag': props.draggable
    }"
    :style="{
        display: _d.show2 ? 'block' : 'none',
        zIndex: _d.zIndex
    }"
    @click="maskClick()">
      <div class="m-dialog-modal">
          <div class="m-dialog-cell">
              <div class="m-dialog-container"
                  :style="{
                      width: _d.width, 
                      maxWidth: _d.maxWidth,
                      transform: `translate(${_d.drag.resultX}px, ${_d.drag.resultY}px)`,
                  }">
                  <div class="m-dialog"
                      ref="mDialogRef"
                      @click.stop>
                      <div class="m-dialog-title"
                          @mousedown="dragDown">
                          <template v-if="title">{{title}}</template>
                          <slot v-else name="title"></slot>
                          <div class="m-dialog-close" @click="handleCancel()">
                              <svg focusable="false" class="" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg>
                          </div>
                      </div>
                      <div class="m-dialog-content" :style="bodyStyle">
                          <slot></slot>
                      </div>
                      <div class="m-dialog-footer">
                          <button v-if="props.showCancel" class="btn" @click="handleCancel()">{{cancelText}}</button>
                          <button v-if="props.showOk" :loading="props.okLoading" class="btn" type="primary" @click="handleOk()">{{okText}}</button>
                      </div>
                  </div>
              </div>
          </div>
      </div>
</div>
</template>

<script setup>
    import { ref, reactive, watch, onBeforeMount, onBeforeUnmount } from 'vue'

  const mDialogWrapperRef = ref();
  const mDialogRef = ref();

    const emit = defineEmits(['update:visible', 'ok', 'cancel', 'closed'])

    const props = defineProps({
        visible: {
            type: Boolean,
            default: false
        },
        width: {
            type: String,
            default: ''
        },
        maxWidth: {
            type: String,
            default: ''
        },
        title: {
            type: String,
            default: ''
        },
        footer: {
            type: Boolean,
            default: true
        },
        showOk: {
            type: Boolean,
            default: true
        },
        showCancel: {
            type: Boolean,
            default: true
        },
        okText: {
            type: String,
            default: '确认修改'
        },
        cancelText: {
            type: String,
            default: '暂不修改'
        },
        // 确认按钮-加载中
        okLoading: {
            type: Boolean,
            default: false
        },
        // 点击蒙层是否允许关闭
        maskClosable: {
            type: Boolean,
            default: true
        },
        // 内容样式
        bodyStyle: {
            type: Object,
            default: () => ({})
        },
        // 层级 - 如果设置了就是固定层级,如果不设置从最多层级1000开始往上加
        zIndex: {
            type: Number,
            default: 0
        },
        // 是否加到body节点下
        appendToBody: {
            type: Boolean,
            default: true
        },
        // 当关闭 Dialog 时,销毁其中的元素
        destroyOnClose: {
            type: Boolean,
            default: true
        },
        // 为 Dialog 启用可拖拽功能
        draggable: {
            type: Boolean,
            default: false
        }
    })

    const _d = reactive({
        show1: false, // 控制v-if
        show2: false, // 控制display
        show3: false, // 控制动画
        zIndex: 1000, // 最低层级
        width: !props.width && !props.maxWidth ? '400px' : props.width, // 宽度
        maxWidth: props.maxWidth, // 最大宽度

        // 拖动参数
        drag: {
            // 是否点下
            isDown: false,
            // 整个页面你最大宽高
            pageWidth: 0,
            pageHeight: 0,
            // 弹窗宽高
            dialogWidth: 0,
            dialogHeight: 0,
            // 左右最大移动距离
            minX: 0,
            maxX: 0,
            minY: 0,
            maxY: 0,
            // 移动结果
            resultX: 0,
            resultY: 0,
            // 鼠标点下是历史移动距离
            startX: 0,
            startY: 0,
            // 鼠标点下时相对于page的位置
            downX: 0,
            downY: 0,
            // 鼠标移动位置
            moveX: 0,
            moveY: 0,
        }
    })

    watch(() => props.visible, (newVal) => {
        setVisible();
    })

    onBeforeMount(() => {
        setVisible();
        // 绑定鼠标事件
        window.addEventListener('mousemove', dragMove);
        window.addEventListener('mouseup', dragUp);
    })

    onBeforeUnmount(() => {
        // 如果appendToBody属性为true, 移除掉插入到body上面的弹框组件,别说这一点我都忘了,严谨
        let $el = mDialogWrapperRef.value;
        if (props.appendToBody && $el && $el.parentNode) {
            $el.parentNode.removeChild($el);
        }
        // 解绑鼠标事件
        window.removeEventListener('mousemove', dragMove);
        window.removeEventListener('mouseup', dragUp);
    })

    // 设置显示状态
    function setVisible () {
        if(props.visible) {
            new Promise((resolve, reject) => {
                if(!_d.show1) { // 第一次通过v-if添加节点到dom树
                    setZIndex();
                    _d.show1 = true;
                    _d.show2 = true;
                    setTimeout(() => {
                        // 判断是否加到body节点下
                        if(props.appendToBody) {
                            let lastChild = 
                            document.body.appendChild(mDialogWrapperRef.value);
                        }
                        setTimeout(() => {
                            resolve();
                        }, 15);
                    }, 15);
                } else { // 关闭后不删除节点,再显示弹窗
                    _d.show2 = true;
                    setTimeout(() => {
                        resolve();
                    }, 30);
                }
            }).then(() => {
                document.body.style.overflow = "hidden";
                _d.show3 = true;
            })
        } else { // 关闭弹窗
            _d.show3 = false; // 关闭时动画效果
            setTimeout(() => {
                _d.show2 = false; // 设置display:none
                if(props.destroyOnClose) {
                    _d.show1 = false; // 通过v-if销毁节点
                }
                document.body.style.overflow = "";
                emit('closed');
            }, 250)
        }
    }

    // 显示的时候设置z-index
    function setZIndex() {
        let max = 1000;
        // 判断是否有自定义的层级
        if(props.zIndex) {
            max = props.zIndex;
        } else {
            let aMd = [...document.querySelectorAll('.m-dialog.show')];
            aMd.forEach(obj => {
                let num = getStyle(obj, 'z-index');
                if(max <= num) {
                    max = num+1;
                }
            })
        }
        _d.zIndex = max;
    }

    // 获取样式
    function getStyle (obj, name) {
        if(window.getComputedStyle) {
            return getComputedStyle(obj, null)[name];
        } else {
            return obj.currentStyle[name];
        }
    }

    // 确认
    function handleOk() {
        emit('ok');
    }

    // 取消
    function handleCancel() {
        emit('update:visible', false);
        emit('cancel');
    }

    // 蒙层点击
    function maskClick () {
        if(props.maskClosable) {
            emit('update:visible', false);
        }
    }

    // 拖动 ----------------------------------------------------
    function dragDown(e) {
        if(!props.draggable) {
            return;
        }
        // 是否按下
        _d.drag.isDown = true;
        // 页面宽高
        _d.drag.pageWidth = mDialogWrapperRef.value.clientWidth;
        _d.drag.pageHeight = mDialogWrapperRef.value.clientHeight;
        // 弹窗宽高
        _d.drag.dialogWidth = mDialogRef.value.clientWidth;
        _d.drag.dialogHeight = mDialogRef.value.clientHeight;

        // 获取弹窗到页面左上角的距离
        let dis = getDistanceBody(mDialogRef.value);
        // 计算边界
        let minX = -dis.left;
        let minY = -dis.top;
        let maxX = _d.drag.pageWidth - _d.drag.dialogWidth - dis.left;
        let maxY = _d.drag.pageHeight - _d.drag.dialogHeight - dis.top;
        if(minX > 0) {
            minX = 0;
        }
        if(minY > 0) {
            minY = 0;
        }
        if(maxX > _d.drag.pageWidth - _d.drag.dialogWidth) {
            maxX = _d.drag.pageWidth - _d.drag.dialogWidth;
        }
        if(maxY > _d.drag.pageHeight - _d.drag.dialogHeight) {
            maxY = _d.drag.pageHeight - _d.drag.dialogHeight;
        }
        _d.drag.minX = minX;
        _d.drag.maxX = maxX;
        _d.drag.minY = minY;
        _d.drag.maxY = maxY;
        // 开始位置
        _d.drag.startX = _d.drag.resultX;
        _d.drag.startY = _d.drag.resultY;
        // 鼠标点下时相对于page的位置
        _d.drag.downX = e.pageX;
        _d.drag.downY = e.pageY;
    }
    function dragMove(e) {
        if(!props.draggable) {
            return;
        }
        if(!_d.drag.isDown) {
            return;
        }
        // 移动距离
        _d.moveX = e.pageX-_d.drag.downX;
        _d.moveY = e.pageY-_d.drag.downY;
        // 涉及结果位置
        let resultX = _d.drag.startX+_d.moveX;
        let resultY = _d.drag.startY+_d.moveY;
        if(resultX < _d.drag.minX) {
            resultX = _d.drag.minX;
        }
        if(resultX > _d.drag.maxX) {
            resultX = _d.drag.maxX;
        }
        if(resultY < _d.drag.minY) {
            resultY = _d.drag.minY;
        }
        if(resultY > _d.drag.maxY) {
            resultY = _d.drag.maxY;
        }
        _d.drag.resultX = resultX;
        _d.drag.resultY = resultY;
    }
    // 鼠标抬起
    function dragUp(e) {
        if(!props.draggable) {
            return;
        }
        if(!_d.drag.isDown) {
            return;
        }
        _d.drag.isDown = false;
    }
    // 获取节点到body的高度
    function getDistanceBody (obj) {
        var oBody = document.body;
        var oHtml = document.documentElement;
        var oParent = null;
        var oDistance = {
            top: 0,
            left: 0
        }
        do {
            oDistance.top += obj.offsetTop;
            oDistance.left += obj.offsetLeft;
            oParent = obj.offsetParent;
            obj = oParent;
        } while(oParent && oParent != oBody && oParent != oHtml)

        return oDistance;
    }


</script>

<style lang="less" scoped>
.m-dialog-wrapper {
    position: fixed;
    z-index: 1000;
    top: 0;
    right: 0;
    left: 0;
    bottom: 0;
    background: rgba(0,0,0,0.25);
    transition: opacity .25s;
    opacity: 0;
    overflow: auto;
    &.show {
        opacity: 1;
        .m-dialog {
            transform: scale(1);
        }
    }
    &.is-drag {
        -moz-user-select:none; /*火狐*/
        -webkit-user-select:none; /*webkit浏览器*/
        -ms-user-select:none; /*IE10*/
        -khtml-user-select:none; /*早期浏览器*/
        user-select:none;
        .m-dialog-title {
            cursor: move;
        }
    }
    .m-dialog-modal {
        display: table;
        padding: 20px 0 40px;
        min-height: 100%;
        min-width: 100%;
        box-sizing: border-box;
    }
    .m-dialog-cell {
        display: table-cell;
        vertical-align: middle;
    }
    .m-dialog-container {
        margin: 0 auto;
    }
    .m-dialog {
        position: relative;
        z-index: 2;
        border-radius: 2px;
        overflow: hidden;
        background: #fff;
        transition: transform .25s;
        transform: scale(0.9);
        box-shadow: 0 3px 6px -4px #0000001f, 0 6px 16px #00000014, 0 9px 28px 8px #0000000d;
        .m-dialog-title {
            position: relative;
            box-sizing: border-box;
            padding: 16px 24px;
            border-bottom: 1px solid #f0f0f0;
            color: #000;
            font-size: 16px;
            line-height: 22px;
            word-wrap: break-word;
            min-height: 55px;
            .m-dialog-close {
                position: absolute;
                top: 50%;
                right: 0;
                margin-top: -27px;
                width: 54px;
                height: 54px;
                display: flex;
                justify-content: center;
                align-items: center;
                font-size: 16px;
                color: #666;
                cursor: pointer;
                &:hover {
                    color: #333;
                }
            }
        }
        .m-dialog-content {
            padding: 24px;
            min-height: 100px;
        }
        .m-dialog-footer {
            padding: 10px 16px;
        text-align: right;
        background: transparent;
        border-top: 1px solid #f0f0f0;
        border-radius: 0 0 2px 2px;
            .btn {
                padding: 4px 15px;
                font-size: 14px;
                color: #333;
                border: 1px solid #d9d9d9;
                background: #fff;
                height: 32px;
                font-weight: 400;
                cursor: pointer;
                outline: medium;
                border-radius: 2px;
                &:not(:last-child) {
                    margin-right: 8px;
                }
            }
        }
    }    
}
</style>

项目地址:codesandbox上测试项目

如果将配置项(:appendToBody="false")设置为false,不添加到body下,使用是没有问题的。设置为true,添加到body后,使用了预览图片功能,之后就会报错。希望有人帮忙找出报错原因,及解决办法

回复
1个回答
avatar
test
2024-06-23

试了一下,这样似乎是可以的。

  • src/components/mDialog/index.vue
<!-- 使用方法
<m-dialog v-model:visible="_d.visible" 
      title="产品信息编辑"
      width="800px"
      :okLoading="_d.loading"
      @ok="onSubmit"
      @closed="() => resetFields()">
</m-dialog>
-->
<template>
  <teleport :disabled="appendToBody">
<div v-if="_d.show1" ref="mDialogWrapperRef"
    class="m-dialog-wrapper" 
    :class="{
        show: _d.show3,
        'is-drag': props.draggable
    }"
    :style="{
        display: _d.show2 ? 'block' : 'none',
        zIndex: _d.zIndex
    }"
    @click="maskClick()">
      <div class="m-dialog-modal">
          <div class="m-dialog-cell">
              <div class="m-dialog-container"
                  :style="{
                      width: _d.width, 
                      maxWidth: _d.maxWidth,
                      transform: `translate(${_d.drag.resultX}px, ${_d.drag.resultY}px)`,
                  }">
                  <div class="m-dialog"
                      ref="mDialogRef"
                      @click.stop>
                      <div class="m-dialog-title"
                          @mousedown="dragDown">
                          <template v-if="title">{{title}}</template>
                          <slot v-else name="title"></slot>
                          <div class="m-dialog-close" @click="handleCancel()">
                              <svg focusable="false" class="" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg>
                          </div>
                      </div>
                      <div class="m-dialog-content" :style="bodyStyle">
                          <slot></slot>
                      </div>
                      <div class="m-dialog-footer">
                          <button v-if="props.showCancel" class="btn" @click="handleCancel()">{{cancelText}}</button>
                          <button v-if="props.showOk" :loading="props.okLoading" class="btn" type="primary" @click="handleOk()">{{okText}}</button>
                      </div>
                  </div>
              </div>
          </div>
      </div>
</div>
  </teleport>
</template>

<script setup>
    import { ref, reactive, watch, onBeforeMount, onBeforeUnmount } from 'vue'

  const mDialogWrapperRef = ref();
  const mDialogRef = ref();

    const emit = defineEmits(['update:visible', 'ok', 'cancel', 'closed'])

    const props = defineProps({
        visible: {
            type: Boolean,
            default: false
        },
        width: {
            type: String,
            default: ''
        },
        maxWidth: {
            type: String,
            default: ''
        },
        title: {
            type: String,
            default: ''
        },
        footer: {
            type: Boolean,
            default: true
        },
        showOk: {
            type: Boolean,
            default: true
        },
        showCancel: {
            type: Boolean,
            default: true
        },
        okText: {
            type: String,
            default: '确认修改'
        },
        cancelText: {
            type: String,
            default: '暂不修改'
        },
        // 确认按钮-加载中
        okLoading: {
            type: Boolean,
            default: false
        },
        // 点击蒙层是否允许关闭
        maskClosable: {
            type: Boolean,
            default: true
        },
        // 内容样式
        bodyStyle: {
            type: Object,
            default: () => ({})
        },
        // 层级 - 如果设置了就是固定层级,如果不设置从最多层级1000开始往上加
        zIndex: {
            type: Number,
            default: 0
        },
        // 是否加到body节点下
        appendToBody: {
            type: Boolean,
            default: true
        },
        // 当关闭 Dialog 时,销毁其中的元素
        destroyOnClose: {
            type: Boolean,
            default: true
        },
        // 为 Dialog 启用可拖拽功能
        draggable: {
            type: Boolean,
            default: false
        }
    })

    const _d = reactive({
        show1: false, // 控制v-if
        show2: false, // 控制display
        show3: false, // 控制动画
        zIndex: 1000, // 最低层级
        width: !props.width && !props.maxWidth ? '400px' : props.width, // 宽度
        maxWidth: props.maxWidth, // 最大宽度

        // 拖动参数
        drag: {
            // 是否点下
            isDown: false,
            // 整个页面你最大宽高
            pageWidth: 0,
            pageHeight: 0,
            // 弹窗宽高
            dialogWidth: 0,
            dialogHeight: 0,
            // 左右最大移动距离
            minX: 0,
            maxX: 0,
            minY: 0,
            maxY: 0,
            // 移动结果
            resultX: 0,
            resultY: 0,
            // 鼠标点下是历史移动距离
            startX: 0,
            startY: 0,
            // 鼠标点下时相对于page的位置
            downX: 0,
            downY: 0,
            // 鼠标移动位置
            moveX: 0,
            moveY: 0,
        }
    })

    watch(() => props.visible, (newVal) => {
        setVisible();
    })

    onBeforeMount(() => {
        setVisible();
        // 绑定鼠标事件
        window.addEventListener('mousemove', dragMove);
        window.addEventListener('mouseup', dragUp);
    })

    onBeforeUnmount(() => {
        // 解绑鼠标事件
        window.removeEventListener('mousemove', dragMove);
        window.removeEventListener('mouseup', dragUp);
    })

    // 设置显示状态
    function setVisible () {
        if(props.visible) {
            new Promise((resolve, reject) => {
                if(!_d.show1) { // 第一次通过v-if添加节点到dom树
                    setZIndex();
                    _d.show1 = true;
                    _d.show2 = true;
                    setTimeout(() => {
                        setTimeout(() => {
                            resolve();
                        }, 15);
                    }, 15);
                } else { // 关闭后不删除节点,再显示弹窗
                    _d.show2 = true;
                    setTimeout(() => {
                        resolve();
                    }, 30);
                }
            }).then(() => {
                document.body.style.overflow = "hidden";
                _d.show3 = true;
            })
        } else { // 关闭弹窗
            _d.show3 = false; // 关闭时动画效果
            setTimeout(() => {
                _d.show2 = false; // 设置display:none
                if(props.destroyOnClose) {
                    _d.show1 = false; // 通过v-if销毁节点
                }
                document.body.style.overflow = "";
                emit('closed');
            }, 250)
        }
    }

    // 显示的时候设置z-index
    function setZIndex() {
        let max = 1000;
        // 判断是否有自定义的层级
        if(props.zIndex) {
            max = props.zIndex;
        } else {
            let aMd = [...document.querySelectorAll('.m-dialog.show')];
            aMd.forEach(obj => {
                let num = getStyle(obj, 'z-index');
                if(max <= num) {
                    max = num+1;
                }
            })
        }
        _d.zIndex = max;
    }

    // 获取样式
    function getStyle (obj, name) {
        if(window.getComputedStyle) {
            return getComputedStyle(obj, null)[name];
        } else {
            return obj.currentStyle[name];
        }
    }

    // 确认
    function handleOk() {
        emit('ok');
    }

    // 取消
    function handleCancel() {
        emit('update:visible', false);
        emit('cancel');
    }

    // 蒙层点击
    function maskClick () {
        if(props.maskClosable) {
            emit('update:visible', false);
        }
    }

    // 拖动 ----------------------------------------------------
    function dragDown(e) {
        if(!props.draggable) {
            return;
        }
        // 是否按下
        _d.drag.isDown = true;
        // 页面宽高
        _d.drag.pageWidth = mDialogWrapperRef.value.clientWidth;
        _d.drag.pageHeight = mDialogWrapperRef.value.clientHeight;
        // 弹窗宽高
        _d.drag.dialogWidth = mDialogRef.value.clientWidth;
        _d.drag.dialogHeight = mDialogRef.value.clientHeight;

        // 获取弹窗到页面左上角的距离
        let dis = getDistanceBody(mDialogRef.value);
        // 计算边界
        let minX = -dis.left;
        let minY = -dis.top;
        let maxX = _d.drag.pageWidth - _d.drag.dialogWidth - dis.left;
        let maxY = _d.drag.pageHeight - _d.drag.dialogHeight - dis.top;
        if(minX > 0) {
            minX = 0;
        }
        if(minY > 0) {
            minY = 0;
        }
        if(maxX > _d.drag.pageWidth - _d.drag.dialogWidth) {
            maxX = _d.drag.pageWidth - _d.drag.dialogWidth;
        }
        if(maxY > _d.drag.pageHeight - _d.drag.dialogHeight) {
            maxY = _d.drag.pageHeight - _d.drag.dialogHeight;
        }
        _d.drag.minX = minX;
        _d.drag.maxX = maxX;
        _d.drag.minY = minY;
        _d.drag.maxY = maxY;
        // 开始位置
        _d.drag.startX = _d.drag.resultX;
        _d.drag.startY = _d.drag.resultY;
        // 鼠标点下时相对于page的位置
        _d.drag.downX = e.pageX;
        _d.drag.downY = e.pageY;
    }
    function dragMove(e) {
        if(!props.draggable) {
            return;
        }
        if(!_d.drag.isDown) {
            return;
        }
        // 移动距离
        _d.moveX = e.pageX-_d.drag.downX;
        _d.moveY = e.pageY-_d.drag.downY;
        // 涉及结果位置
        let resultX = _d.drag.startX+_d.moveX;
        let resultY = _d.drag.startY+_d.moveY;
        if(resultX < _d.drag.minX) {
            resultX = _d.drag.minX;
        }
        if(resultX > _d.drag.maxX) {
            resultX = _d.drag.maxX;
        }
        if(resultY < _d.drag.minY) {
            resultY = _d.drag.minY;
        }
        if(resultY > _d.drag.maxY) {
            resultY = _d.drag.maxY;
        }
        _d.drag.resultX = resultX;
        _d.drag.resultY = resultY;
    }
    // 鼠标抬起
    function dragUp(e) {
        if(!props.draggable) {
            return;
        }
        if(!_d.drag.isDown) {
            return;
        }
        _d.drag.isDown = false;
    }
    // 获取节点到body的高度
    function getDistanceBody (obj) {
        var oBody = document.body;
        var oHtml = document.documentElement;
        var oParent = null;
        var oDistance = {
            top: 0,
            left: 0
        }
        do {
            oDistance.top += obj.offsetTop;
            oDistance.left += obj.offsetLeft;
            oParent = obj.offsetParent;
            obj = oParent;
        } while(oParent && oParent != oBody && oParent != oHtml)

        return oDistance;
    }


</script>

<style lang="less" scoped>
.m-dialog-wrapper {
    position: fixed;
    z-index: 1000;
    top: 0;
    right: 0;
    left: 0;
    bottom: 0;
    background: rgba(0,0,0,0.25);
    transition: opacity .25s;
    opacity: 0;
    overflow: auto;
    &.show {
        opacity: 1;
        .m-dialog {
            transform: scale(1);
        }
    }
    &.is-drag {
        -moz-user-select:none; /*火狐*/
        -webkit-user-select:none; /*webkit浏览器*/
        -ms-user-select:none; /*IE10*/
        -khtml-user-select:none; /*早期浏览器*/
        user-select:none;
        .m-dialog-title {
            cursor: move;
        }
    }
    .m-dialog-modal {
        display: table;
        padding: 20px 0 40px;
        min-height: 100%;
        min-width: 100%;
        box-sizing: border-box;
    }
    .m-dialog-cell {
        display: table-cell;
        vertical-align: middle;
    }
    .m-dialog-container {
        margin: 0 auto;
    }
    .m-dialog {
        position: relative;
        z-index: 2;
        border-radius: 2px;
        overflow: hidden;
        background: #fff;
        transition: transform .25s;
        transform: scale(0.9);
        box-shadow: 0 3px 6px -4px #0000001f, 0 6px 16px #00000014, 0 9px 28px 8px #0000000d;
        .m-dialog-title {
            position: relative;
            box-sizing: border-box;
            padding: 16px 24px;
            border-bottom: 1px solid #f0f0f0;
            color: #000;
            font-size: 16px;
            line-height: 22px;
            word-wrap: break-word;
            min-height: 55px;
            .m-dialog-close {
                position: absolute;
                top: 50%;
                right: 0;
                margin-top: -27px;
                width: 54px;
                height: 54px;
                display: flex;
                justify-content: center;
                align-items: center;
                font-size: 16px;
                color: #666;
                cursor: pointer;
                &:hover {
                    color: #333;
                }
            }
        }
        .m-dialog-content {
            padding: 24px;
            min-height: 100px;
        }
        .m-dialog-footer {
            padding: 10px 16px;
        text-align: right;
        background: transparent;
        border-top: 1px solid #f0f0f0;
        border-radius: 0 0 2px 2px;
            .btn {
                padding: 4px 15px;
                font-size: 14px;
                color: #333;
                border: 1px solid #d9d9d9;
                background: #fff;
                height: 32px;
                font-weight: 400;
                cursor: pointer;
                outline: medium;
                border-radius: 2px;
                &:not(:last-child) {
                    margin-right: 8px;
                }
            }
        }
    }    
}
</style>
回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容