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
@@ -5,7 +5,7 @@ | @@ -5,7 +5,7 @@ | ||
5 | <Modal | 5 | <Modal |
6 | v-model="modal1" | 6 | v-model="modal1" |
7 | title="Common Modal dialog box title" | 7 | title="Common Modal dialog box title" |
8 | - :mask="false" | 8 | + dragable |
9 | @on-ok="ok" | 9 | @on-ok="ok" |
10 | @on-cancel="cancel"> | 10 | @on-cancel="cancel"> |
11 | <p>Content of dialog</p> | 11 | <p>Content of dialog</p> |
src/components/modal/modal.vue
@@ -6,13 +6,16 @@ | @@ -6,13 +6,16 @@ | ||
6 | <div :class="wrapClasses" @click="handleWrapClick"> | 6 | <div :class="wrapClasses" @click="handleWrapClick"> |
7 | <transition :name="transitionNames[0]" @after-leave="animationFinish"> | 7 | <transition :name="transitionNames[0]" @after-leave="animationFinish"> |
8 | <div :class="classes" :style="mainStyles" v-show="visible"> | 8 | <div :class="classes" :style="mainStyles" v-show="visible"> |
9 | - <div :class="contentClasses"> | 9 | + <div :class="contentClasses" ref="content" :style="contentStyles"> |
10 | <a :class="[prefixCls + '-close']" v-if="closable" @click="close"> | 10 | <a :class="[prefixCls + '-close']" v-if="closable" @click="close"> |
11 | <slot name="close"> | 11 | <slot name="close"> |
12 | <Icon type="ios-close"></Icon> | 12 | <Icon type="ios-close"></Icon> |
13 | </slot> | 13 | </slot> |
14 | </a> | 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 | <div :class="[prefixCls + '-body']"><slot></slot></div> | 19 | <div :class="[prefixCls + '-body']"><slot></slot></div> |
17 | <div :class="[prefixCls + '-footer']" v-if="!footerHide"> | 20 | <div :class="[prefixCls + '-footer']" v-if="!footerHide"> |
18 | <slot name="footer"> | 21 | <slot name="footer"> |
@@ -34,6 +37,8 @@ | @@ -34,6 +37,8 @@ | ||
34 | import Emitter from '../../mixins/emitter'; | 37 | import Emitter from '../../mixins/emitter'; |
35 | import ScrollbarMixins from './mixins-scrollbar'; | 38 | import ScrollbarMixins from './mixins-scrollbar'; |
36 | 39 | ||
40 | + import { on, off } from '../../utils/dom'; | ||
41 | + | ||
37 | const prefixCls = 'ivu-modal'; | 42 | const prefixCls = 'ivu-modal'; |
38 | 43 | ||
39 | export default { | 44 | export default { |
@@ -115,7 +120,14 @@ | @@ -115,7 +120,14 @@ | ||
115 | wrapShow: false, | 120 | wrapShow: false, |
116 | showHead: true, | 121 | showHead: true, |
117 | buttonLoading: false, | 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 | computed: { | 133 | computed: { |
@@ -146,7 +158,9 @@ | @@ -146,7 +158,9 @@ | ||
146 | return [ | 158 | return [ |
147 | `${prefixCls}-content`, | 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,7 +168,9 @@ | ||
154 | let style = {}; | 168 | let style = {}; |
155 | 169 | ||
156 | const width = parseInt(this.width); | 170 | const width = parseInt(this.width); |
157 | - const styleWidth = { | 171 | + const styleWidth = this.dragData.x !== null ? { |
172 | + top: 0 | ||
173 | + } : { | ||
158 | width: width <= 100 ? `${width}%` : `${width}px` | 174 | width: width <= 100 ? `${width}%` : `${width}px` |
159 | }; | 175 | }; |
160 | 176 | ||
@@ -164,6 +180,22 @@ | @@ -164,6 +180,22 @@ | ||
164 | 180 | ||
165 | return style; | 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 | localeOkText () { | 199 | localeOkText () { |
168 | if (this.okText === undefined) { | 200 | if (this.okText === undefined) { |
169 | return this.t('i.modal.okText'); | 201 | return this.t('i.modal.okText'); |
@@ -219,6 +251,51 @@ | @@ -219,6 +251,51 @@ | ||
219 | }, | 251 | }, |
220 | animationFinish() { | 252 | animationFinish() { |
221 | this.$emit('on-hidden'); | 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 | mounted () { | 301 | mounted () { |
src/styles/components/modal.less
@@ -44,6 +44,17 @@ | @@ -44,6 +44,17 @@ | ||
44 | &-no-mask{ | 44 | &-no-mask{ |
45 | pointer-events: auto; | 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 | &-header { | 60 | &-header { |