当前位置:   article > 正文

vue + element-ui 实现拖拽Dialog_element ui vue2 弹框可拖动

element ui vue2 弹框可拖动

项目使用vue2+element-ui 封装dialog 弹窗并实现拖拽移动位置功能

1、项目安装element-ui 并引入

npm i element-ui -S
//在main.js中引入
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
  • 1
  • 2
  • 3
  • 4
  • 5

2.封装element-ui的 Dialog 组件
在components中新建dialog.vue

<template>
  <el-dialog  v-el-drag-dialog :width="width" :modal-append-to-body="false" :close-on-click-modal="false" :before-close="handleClose" :visible.sync="visible">
    <template slot="title">{{ title }}</template>
    <template>
      <component ref="page" :is="page" :param="param" @ok="onPageOk" @cancel="onPageCancel"></component>
    </template>
    <span slot="footer" class="dialog-footer" v-if="buttons && buttons.length > 0">
      <el-button v-for="button of buttons" @click="buttonClicked(button)" :key="button.name" type="primary" style="margin-right: 10px">{{ button.name }}</el-button>
    </span>
  </el-dialog>
</template>

<script>
import elDragDialog from '@/directives/el-drag-dialog' // base on element-ui
export default {
  name: 'DragDialogDemo',
  directives: { elDragDialog },
  data: function () {
    return {
      title: 'Title',
      page: '',
      width: '40%',
      visible: true,
      param: '',
      buttons: [] // 每个元素是一个按钮,{ name: "确定", click: function() {} }, 从包含的page的buttons属性复制过来
    }
  },
  methods: {
    buttonClicked (button) {
      button.click.bind(this.$refs.page).call() // 将按钮的事件绑定到page对象上
    },
    onPageOk (result) {
      this.$emit('ok', result)
      this.visible = false
    },
    onPageCancel () {
      this.$emit('cancel')
      this.visible = false
    },
    handleClose (done) {
      this.$emit('cancel')
      done()
    }
  }
}
</script>

<style lang="scss" scoped >
/deep/ .el-dialog {
  border-radius: 5px;
  transform: none;
  left: 0;
  position: relative;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
}

.el-dialog__header,
.el-dialog__body {
  border-bottom: 1px solid gainsboro;
  font-weight: 600;
  font-size: 18px;
  color: #409EFF;
  max-height: 80vh !important;
  overflow-y: auto;
}
</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

2、封装打开Dialog方法

/** 加载页面 */
  load(path) {
    return new Promise((resolve, reject) => {
      let name = names[path];
      if (name != null) {
        let page = pages[path];
        resolve([name, page]);
        return;
      }

      console.log(`加载页面: ${path}`);
      import("@/pages/" + path + ".vue")
        .then(module => {
          let page = module.default;

          name = "page" + sn++;
          names[path] = name;
          pages[path] = page;
          Vue.component(name, page);

          resolve([name, page]);
        })
        .catch(e => {
          console.log(`加载页面失败: ${path}`);

          reject(e);
        });
    });
  },
  /** 弹出页面 */
  popup(title, path, param, width) {
    return new Promise((resolve, reject) => {
      load(path).then(([name, page]) => {
        console.log(`弹出页面: ${title}: ${path}`);
        // 准备对话框
        let dialog = new Vue(Dialog);
        dialog.title = title;
        dialog.page = name;
        dialog.param = param;
        if (width == undefined || width == 'undefined ') {
          dialog.width = '40%';
        } else {
          dialog.width = width + '%';
        }
        dialog.buttons = page.buttons; // 将page中的buttons复制到dialog中
        dialog.$on("ok", (result) => {
          resolve(result);
        });

        // 显示对话框
        let div1 = document.createElement('div');
        let div2 = document.createElement('div');
        div1.appendChild(div2);
        let body = document.getElementsByTagName('body')[0];
        body.appendChild(div1);

        dialog.$mount(div2);
        dialog.$on("cancel", function () {
          resolve();
        });
        dialog.$on("close", function () {
          body.removeChild(div1);
        });
      });
    });
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

3、封装拖拽自定义指令 ,在directives文件夹中新建el-drag-dialog文件夹,文件夹内新建drag.js 和index.js 以下是代码
drag.js

export default {
  bind(el, binding, vnode) {
    const dialogHeaderEl = el.querySelector('.el-dialog__header')
    const dragDom = el.querySelector('.el-dialog')
    dialogHeaderEl.style.cssText += ';cursor:move;'
    dragDom.style.cssText += ';top:0px;'
    const getStyle = (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 dragDomWidth = dragDom.offsetWidth
      const dragDomHeight = dragDom.offsetHeight

      const screenWidth = document.body.clientWidth
      const screenHeight = document.body.clientHeight

      const minDragDomLeft = dragDom.offsetLeft
      const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth

      const minDragDomTop = dragDom.offsetTop
      const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomHeight

      // 获取到的值带px 正则匹配替换
      let styL = getStyle(dragDom, 'left')
      let styT = getStyle(dragDom, 'top')

      //
      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
        }
        // 移动当前元素
        console.log( `;left:${left + styL}px;top:${top + styT}px;`)
        dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`
        vnode.child.$emit('dragDialog')
      }

      document.onmouseup = function(e) {
        document.onmousemove = null
        document.onmouseup = null
      }
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

index.js

import drag from './drag'

const install = function(Vue) {
  Vue.directive('el-drag-dialog', drag)
}

if (window.Vue) {
  window['el-drag-dialog'] = drag
  Vue.use(install); // eslint-disable-line
}

drag.install = install
export default drag
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

以上就是所有代码啦。通过popup方式打开Dialog后就可以在可视窗口内自由拖拽移动了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/709175
推荐阅读
相关标签
  

闽ICP备14008679号