Commit d4b59a9adbeacacf4ed8c4e2d55f3954227bc4da
1 parent
1c7289e9
Modal add dragable prop
Showing
3 changed files
with
94 additions
and
6 deletions
Show diff stats
examples/routers/modal.vue
src/components/modal/modal.vue
... | ... | @@ -6,13 +6,16 @@ |
6 | 6 | <div :class="wrapClasses" @click="handleWrapClick"> |
7 | 7 | <transition :name="transitionNames[0]" @after-leave="animationFinish"> |
8 | 8 | <div :class="classes" :style="mainStyles" v-show="visible"> |
9 | - <div :class="contentClasses"> | |
9 | + <div :class="contentClasses" ref="content" :style="contentStyles"> | |
10 | 10 | <a :class="[prefixCls + '-close']" v-if="closable" @click="close"> |
11 | 11 | <slot name="close"> |
12 | 12 | <Icon type="ios-close"></Icon> |
13 | 13 | </slot> |
14 | 14 | </a> |
15 | - <div :class="[prefixCls + '-header']" v-if="showHead"><slot name="header"><div :class="[prefixCls + '-header-inner']">{{ title }}</div></slot></div> | |
15 | + <div :class="[prefixCls + '-header']" | |
16 | + @mousedown="handleMoveStart" | |
17 | + v-if="showHead" | |
18 | + ><slot name="header"><div :class="[prefixCls + '-header-inner']">{{ title }}</div></slot></div> | |
16 | 19 | <div :class="[prefixCls + '-body']"><slot></slot></div> |
17 | 20 | <div :class="[prefixCls + '-footer']" v-if="!footerHide"> |
18 | 21 | <slot name="footer"> |
... | ... | @@ -34,6 +37,8 @@ |
34 | 37 | import Emitter from '../../mixins/emitter'; |
35 | 38 | import ScrollbarMixins from './mixins-scrollbar'; |
36 | 39 | |
40 | + import { on, off } from '../../utils/dom'; | |
41 | + | |
37 | 42 | const prefixCls = 'ivu-modal'; |
38 | 43 | |
39 | 44 | export default { |
... | ... | @@ -115,7 +120,14 @@ |
115 | 120 | wrapShow: false, |
116 | 121 | showHead: true, |
117 | 122 | buttonLoading: false, |
118 | - visible: this.value | |
123 | + visible: this.value, | |
124 | + dragData: { | |
125 | + x: null, | |
126 | + y: null, | |
127 | + dragX: null, | |
128 | + dragY: null, | |
129 | + dragging: false | |
130 | + } | |
119 | 131 | }; |
120 | 132 | }, |
121 | 133 | computed: { |
... | ... | @@ -146,7 +158,9 @@ |
146 | 158 | return [ |
147 | 159 | `${prefixCls}-content`, |
148 | 160 | { |
149 | - [`${prefixCls}-content-no-mask`]: !this.showMask | |
161 | + [`${prefixCls}-content-no-mask`]: !this.showMask, | |
162 | + [`${prefixCls}-content-drag`]: this.dragable, | |
163 | + [`${prefixCls}-content-dragging`]: this.dragable && this.dragData.dragging | |
150 | 164 | } |
151 | 165 | ]; |
152 | 166 | }, |
... | ... | @@ -154,7 +168,9 @@ |
154 | 168 | let style = {}; |
155 | 169 | |
156 | 170 | const width = parseInt(this.width); |
157 | - const styleWidth = { | |
171 | + const styleWidth = this.dragData.x !== null ? { | |
172 | + top: 0 | |
173 | + } : { | |
158 | 174 | width: width <= 100 ? `${width}%` : `${width}px` |
159 | 175 | }; |
160 | 176 | |
... | ... | @@ -164,6 +180,22 @@ |
164 | 180 | |
165 | 181 | return style; |
166 | 182 | }, |
183 | + contentStyles () { | |
184 | + let style = {}; | |
185 | + | |
186 | + if (this.dragable) { | |
187 | + if (this.dragData.x !== null) style.left = `${this.dragData.x}px`; | |
188 | + if (this.dragData.y !== null) style.top = `${this.dragData.y}px`; | |
189 | + const width = parseInt(this.width); | |
190 | + const styleWidth = { | |
191 | + width: width <= 100 ? `${width}%` : `${width}px` | |
192 | + }; | |
193 | + | |
194 | + Object.assign(style, styleWidth); | |
195 | + } | |
196 | + | |
197 | + return style; | |
198 | + }, | |
167 | 199 | localeOkText () { |
168 | 200 | if (this.okText === undefined) { |
169 | 201 | return this.t('i.modal.okText'); |
... | ... | @@ -219,6 +251,51 @@ |
219 | 251 | }, |
220 | 252 | animationFinish() { |
221 | 253 | this.$emit('on-hidden'); |
254 | + }, | |
255 | + handleMoveStart (event) { | |
256 | + if (!this.dragable) return false; | |
257 | + | |
258 | + const $content = this.$refs.content; | |
259 | + const rect = $content.getBoundingClientRect(); | |
260 | + this.dragData.x = rect.x; | |
261 | + this.dragData.y = rect.y; | |
262 | + | |
263 | + const distance = { | |
264 | + x: event.clientX, | |
265 | + y: event.clientY | |
266 | + }; | |
267 | + | |
268 | + this.dragData.dragX = distance.x; | |
269 | + this.dragData.dragY = distance.y; | |
270 | + | |
271 | + this.dragData.dragging = true; | |
272 | + | |
273 | + on(window, 'mousemove', this.handleMoveMove); | |
274 | + on(window, 'mouseup', this.handleMoveEnd); | |
275 | + }, | |
276 | + handleMoveMove (event) { | |
277 | + if (!this.dragData.dragging) return false; | |
278 | + | |
279 | + const distance = { | |
280 | + x: event.clientX, | |
281 | + y: event.clientY | |
282 | + }; | |
283 | + | |
284 | + const diff_distance = { | |
285 | + x: distance.x - this.dragData.dragX, | |
286 | + y: distance.y - this.dragData.dragY | |
287 | + }; | |
288 | + | |
289 | + this.dragData.x += diff_distance.x; | |
290 | + this.dragData.y += diff_distance.y; | |
291 | + | |
292 | + this.dragData.dragX = distance.x; | |
293 | + this.dragData.dragY = distance.y; | |
294 | + }, | |
295 | + handleMoveEnd (event) { | |
296 | + this.dragData.dragging = false; | |
297 | + off(window, 'mousemove', this.handleMoveMove); | |
298 | + off(window, 'mouseup', this.handleMoveEnd); | |
222 | 299 | } |
223 | 300 | }, |
224 | 301 | mounted () { | ... | ... |
src/styles/components/modal.less
... | ... | @@ -44,6 +44,17 @@ |
44 | 44 | &-no-mask{ |
45 | 45 | pointer-events: auto; |
46 | 46 | } |
47 | + &-drag{ | |
48 | + position: absolute; | |
49 | + .@{modal-prefix-cls}-header{ | |
50 | + cursor: move; | |
51 | + } | |
52 | + } | |
53 | + &-dragging{ | |
54 | + -webkit-user-select: none; | |
55 | + -moz-user-select: none; | |
56 | + user-select: none; | |
57 | + } | |
47 | 58 | } |
48 | 59 | |
49 | 60 | &-header { | ... | ... |