美文网首页vue
ant-design-vue弹窗二次封装,使其可自由拖动

ant-design-vue弹窗二次封装,使其可自由拖动

作者: NemoExpress | 来源:发表于2022-01-24 09:25 被阅读0次

使用的antdv组件库中的弹窗是没法拖动的,现在需求要使其标题栏可以在按住鼠标的时候弹窗可以自由拖动

components目录下建立两个文件


组件目录
  1. index.vue内容如下
<!--
 * Description  : 可拖拽antdv 弹窗的封装
 * Date         :2022-01-20 16:41:46
 * LastEditors  :Xuwei
 * LastEditTime :2022-01-21 17:35:06
 * FilePath     :\WebGUI\src\components\DragModal\index.vue
-->
<template>
  <a-modal
    :class="[modalClass, simpleClass]"
    :visible="visible"
    v-bind="$props"
    :footer="null"
    :bodyStyle="{ padding: 0 }"
    @ok="handleOk"
    @cancel="handleCancel"
  >
    <div class="ant-modal-body" :style="bodyStyle">
      <slot></slot>
    </div>
    <div class="ant-modal-footer relative">
      <slot name="footer"></slot>
    </div>
    <div v-if="!title && title !== ''" slot="title">
      <slot name="title"></slot>
    </div>
  </a-modal>
</template>

<script>
import props from './props.js'
var mouseDownX = 0
var mouseDownY = 0
var deltaX = 0
var deltaY = 0
var sumX = 0
var sumY = 0

var header = null // 标题头部
var contain = null
var modalContent = null

var onmousedown = false
export default {
  name: 'DragModal',
  mixins: [props],
  props: {
    // 容器的类名
    modalClass: {
      type: String,
      default: () => {
        return 'modal-box'
      }
    },
    visible: {
      type: Boolean,
      default: () => {
        return false
      }
    },
    title: {
      type: String,
      default: () => {
        return undefined
      }
    },
    // width: {
    //   type: String,
    //   default: () => {
    //     return '70%'
    //   }
    // },
    footer: {
      type: Boolean,
      default: () => {
        return true
      }
    }
  },
  data() {
    return {}
  },
  computed: {
    simpleClass() {
      return Math.random()
        .toString(36)
        .substring(2)
    }
  },
  watch: {
    visible() {
      this.$nextTick(() => {
        this.initialEvent(this.visible)
      })
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initialEvent(this.visible)
    })
  },
  created() {},
  beforeDestroy() {
    this.removeMove()
    window.removeEventListener('mouseup', this.removeUp, false) // 移除鼠标按下需监听
  },
  methods: {
    // 确定按钮回调
    handleOk(e) {
      this.resetNum()
      this.$emit('ok', e)
    },
    // 取消按钮回调
    handleCancel(e) {
      this.resetNum()
      this.$emit('cancel', e)
    },
    // 弹窗的初始位置初始化
    resetNum() {
      mouseDownX = 0
      mouseDownY = 0
      deltaX = 0
      deltaY = 0
      sumX = 0
      sumY = 0
    },
    // 移动事件
    handleMove(event) {
      const delta1X = event.pageX - mouseDownX
      const delta1Y = event.pageY - mouseDownY
      deltaX = delta1X
      deltaY = delta1Y
      // console.log('delta1X:' + delta1X, 'sumX:' + sumX, 'delta1Y:' + delta1Y, 'sumY:' + sumY)
      modalContent.style.transform = `translate(${delta1X + sumX}px, ${delta1Y +
        sumY}px)`
    },
    // 弹窗初始化
    initialEvent(visible) {
      //   console.log('--------- 初始化')
      //   console.log('simpleClass===>', this.simpleClass)
      //   console.log('document===>', document)
      if (visible) {
        setTimeout(() => {
          window.removeEventListener('mouseup', this.removeUp, false)
          contain = document.getElementsByClassName(this.simpleClass)[0]
          header = contain.getElementsByClassName('ant-modal-header')[0]
          modalContent = contain.getElementsByClassName('ant-modal-content')[0]
          modalContent.style.left = 0
          modalContent.style.transform = 'translate(0px,0px)'
          // console.log('初始化-header:', header)
          // console.log('初始化-contain:', contain)
          // console.log('初始化-modalContent:', modalContent)
          header.style.cursor = 'all-scroll'
          // contain.onmousedown = (e) => {
          header.onmousedown = e => {
            onmousedown = true
            mouseDownX = e.pageX
            mouseDownY = e.pageY
            document.body.onselectstart = () => false
            window.addEventListener('mousemove', this.handleMove, false)
          }

          window.addEventListener('mouseup', this.removeUp, false)
        }, 0)
      }
    },
    // 鼠标停止
    removeMove() {
      window.removeEventListener('mousemove', this.handleMove, false)
    },
    // 鼠标抬起事件
    removeUp(e) {
      // console.log('removeUp')
      document.body.onselectstart = () => true
      if (onmousedown && !(e.pageX === mouseDownX && e.pageY === mouseDownY)) {
        onmousedown = false
        sumX = sumX + deltaX
        sumY = sumY + deltaY
        // console.log('sumX:' + sumX, 'sumY:' + sumY)
      }
      this.removeMove()
    }
  }
}
</script>
  1. props.js(就是antdv弹窗原生自带的所以参数,https://www.antdv.com/components/modal-cn/
export default {
  props: [
    'afterClose', //     Modal 完全关闭后的回调    function    无
    'bodyStyle', //     Modal body 样式    object    {}
    'cancelText', //     取消按钮文字    string| slot    取消
    'centered', //     垂直居中展示 Modal    Boolean    false
    'closable', //     是否显示右上角的关闭按钮    boolean    true
    'closeIcon', //     自定义关闭图标    VNode | slot    -    1.5.0
    'confirmLoading', //     确定按钮 loading    boolean    无
    'destroyOnClose', //     关闭时销毁 Modal 里的子元素    boolean    false
    // 'footer', //     底部内容,当不需要默认底部按钮时,可以设为 :footer="null"    string|slot    确定取消按钮
    'forceRender', //     强制渲染 Modal    boolean    false
    'getContainer', //     指定 Modal 挂载的 HTML 节点    (instance): HTMLElement    () => document.body
    'keyboard', //     是否支持键盘 esc 关闭    boolean    true
    'mask', //     是否展示遮罩    Boolean    true
    'maskClosable', //     点击蒙层是否允许关闭    boolean    true
    'maskStyle', //     遮罩样式    object    {}
    'okText', //     确认按钮文字    string|slot    确定
    'okType', //     确认按钮类型    string    primary
    'okButtonProps', //     ok 按钮 props, 遵循 jsx规范    {props: ButtonProps, on: {}}    -
    'cancelButtonProps', //     cancel 按钮 props, 遵循 jsx规范    {props: ButtonProps, on: {}}    -
    'title', //     标题    string|slot    无
    'visible', // (v-model)    对话框是否可见    boolean    无
    'width', //     宽度    string|number    520
    'wrapClassName', //     对话框外层容器的类名    string    -
    'zIndex', //     设置 Modal 的 z-index    Number    1000
    'dialogStyle', //     可用于设置浮层的样式,调整浮层位置等    object    -    1.6.1
    'dialogClass' //     可用于设置浮层的类名    string
  ]
}
  1. main.js 当中引入
import DragModal from '@/components/DragModal'
Vue.component('DModal', DragModal)

4.调用使用
因为是在main.js当中全局引入了,所以,可以在vue模版文件中直接进行调用。需要注意的是弹窗底部footer确定和取消按钮部分,需要使用插槽重新定义,因为封装d-modal过程中使用的插槽对footer进行了定义

...
 <!-- 删除任务确定对话框 -->
    <d-modal
      centered
      class="modal-bk"
      :title="$t('task.delete')"
      :visible="delShow"
      @cancel="cancelDel"
      @ok="onOkDel"
      :cancelText="$t('cancel')"
      :okText="$t('confirm')"
    >
 <!-- 这里使用插槽重新自定footer的确定和取消按钮 -->
      <template slot="footer"> 
        <a-button @click="cancelDel">
          {{ $t('cancel') }}
        </a-button>
        <a-button type="primary" @click="onOkDel" :loading="confirmLoading">
          {{ $t('confirm') }}
        </a-button>
      </template>
      <div class="modal-body">
        <div class="modal-status">
          <i class="am-icon am-icon-question" />
        </div>
        <div class="modal-content">
          <a-radio-group v-model="valueDel">
            <a-radio :value="0">
              <!-- 只删除这个备份任务 -->
              {{ $t('task.delete.current') }}
            </a-radio>
            <a-radio :value="1">
              <!-- 永久删除这个备份任务和它的镜像文件。 -->
              {{ $t('task.delete.current-forever') }}
            </a-radio>
          </a-radio-group>
        </div>
      </div>
    </d-modal>
...

相关文章

网友评论

    本文标题:ant-design-vue弹窗二次封装,使其可自由拖动

    本文链接:https://www.haomeiwen.com/subject/lsoehrtx.html