实现原理:利用vue创造一个自定义指令,绑定到需要拖拽移动的el-dialog组件上,在自定义指令中处理弹窗拖拽。

1、在src的components文件夹下新建elDialog文件夹,elDialog文件夹下有:index.js、index.vue

index.vue文件代码:

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
<template>
<my-dialog v-model="data"
v-dialogDrag
:visible="visible"
:title="title"
:width="width"
:fullscreen="fullscreen"
:top="top"
:modal="modal"
:modal-append-to-body="modalAppendToBody"
:append-to-body="appendToBody"
:lock-scroll="lockScroll"
:custom-class="customClass"
:close-on-click-modal="closeOnClickModal"
:close-on-press-escape="closeOnPressEscape"
:show-close="showClose"
:center="center"
:before-close="beforeClose"
@opened="opened"
@close="close"
@closed="closed"
@open="open">
<slot name="title" />
<slot />
<slot name="footer" />
</my-dialog>
</template>

<script>
import { Dialog } from 'element-ui'
export default {
components: {
myDialog: Dialog
},
props: {
value: {
type: Boolean,
default: true
},
visible: {
type: Boolean,
default: false
},
title: {
type: String,
default: ''
},
width: {
type: String,
default: '50%'
},
fullscreen: {
type: Boolean,
default: false
},
top: {
type: String,
default: '15vh'
},
modal: {
type: Boolean,
default: true
},
modalAppendToBody: {
type: Boolean,
default: true
},
appendToBody: {
type: Boolean,
default: false
},
lockScroll: {

type: Boolean,
default: true
},
customClass: {
type: String,
default: ''
},
closeOnClickModal: {
type: Boolean,
default: false
},
closeOnPressEscape: {
type: Boolean,
default: true
},

showClose: {
type: Boolean,
default: true
},
center: {
type: Boolean,
default: false
},
beforeClose: {
type: Function,
default: () => {}
}
},
data() {
return {
data: this.value
}
},
watch: {
value() {
this.data = this.value
}
},
mounted() {
},
methods: {
open() {
this.$emit('open')
},
opened() {
this.$emit('opened')
},
close() {
this.$emit('close')
},
closed() {
this.$emit('closed')
}
}
}
</script>

<style>
// 可以自由修改你想要的dialog全局样式
</style>

index.js文件代码:

1
2
3
4
5
6
7
import elDialogComponent from './index.vue'
const elDialog = {
install: function(Vue) {
Vue.component('elDialog', elDialogComponent)
}
}
export default elDialog

2、通过vue的自定义指令v-dialogDrag,实现拖拽的逻辑功能,在utils文件夹下新建dialog.js文件

dialog.js文件代码:

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
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'

// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null)

dialogHeaderEl.onmousedown = (e) => {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - dialogHeaderEl.offsetLeft
const disY = e.clientY - dialogHeaderEl.offsetTop

// 获取到的值带px 正则匹配替换
let styL, styT

// 注意在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, '')
}

document.onmousemove = function(e) {
// 通过事件委托,计算移动的距离
const l = e.clientX - disX
const t = e.clientY - disY

// 移动当前元素
dragDom.style.left = `${l + styL}px`
dragDom.style.top = `${t + styT}px`

// 将此时的位置传出去
// binding.value({x:e.pageX,y:e.pageY})
}

document.onmouseup = function(e) {
document.onmousemove = null
document.onmouseup = null
}
}
}
})

3、在main.js中进行应用

1
2
3
import elDialog from '@/components/elDialog'
Vue.use(elDialog)
import './utils/dialog'