Commit 297648f1e634900ce4e22498f9c061f670c7321f
1 parent
300bd662
fixed #1063
Showing
9 changed files
with
180 additions
and
33 deletions
Show diff stats
examples/routers/spin.vue
... | ... | @@ -181,6 +181,8 @@ |
181 | 181 | </div> |
182 | 182 | <br> |
183 | 183 | 切换显示状态:<i-switch @on-change="spinShow = !spinShow"></i-switch> |
184 | + <Button @click="show">show</Button> | |
185 | + <Button @click="hide">hide</Button> | |
184 | 186 | </div> |
185 | 187 | </template> |
186 | 188 | <script> |
... | ... | @@ -189,6 +191,29 @@ |
189 | 191 | return { |
190 | 192 | spinShow: true |
191 | 193 | } |
194 | + }, | |
195 | + methods: { | |
196 | + show () { | |
197 | + this.$Spin.show({ | |
198 | + render: (h) => { | |
199 | + return h('div', [ | |
200 | + h('Icon', { | |
201 | + props: { | |
202 | + type: 'load-c', | |
203 | + size: 24 | |
204 | + } | |
205 | + }), | |
206 | + h('div', 'Loading') | |
207 | + ]) | |
208 | + } | |
209 | + }); | |
210 | + setTimeout(() => { | |
211 | + this.$Spin.hide(); | |
212 | + }, 3000) | |
213 | + }, | |
214 | + hide () { | |
215 | + this.$Spin.hide(); | |
216 | + } | |
192 | 217 | } |
193 | 218 | } |
194 | 219 | </script> | ... | ... |
1 | +// used for Modal & $Spin | |
2 | +import { getScrollBarSize } from '../../utils/assist'; | |
3 | +export default { | |
4 | + methods: { | |
5 | + checkScrollBar () { | |
6 | + let fullWindowWidth = window.innerWidth; | |
7 | + if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8 | |
8 | + const documentElementRect = document.documentElement.getBoundingClientRect(); | |
9 | + fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left); | |
10 | + } | |
11 | + this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth; | |
12 | + if (this.bodyIsOverflowing) { | |
13 | + this.scrollBarWidth = getScrollBarSize(); | |
14 | + } | |
15 | + }, | |
16 | + setScrollBar () { | |
17 | + if (this.bodyIsOverflowing && this.scrollBarWidth !== undefined) { | |
18 | + document.body.style.paddingRight = `${this.scrollBarWidth}px`; | |
19 | + } | |
20 | + }, | |
21 | + resetScrollBar () { | |
22 | + document.body.style.paddingRight = ''; | |
23 | + }, | |
24 | + addScrollEffect () { | |
25 | + this.checkScrollBar(); | |
26 | + this.setScrollBar(); | |
27 | + document.body.style.overflow = 'hidden'; | |
28 | + }, | |
29 | + removeScrollEffect() { | |
30 | + document.body.style.overflow = ''; | |
31 | + this.resetScrollBar(); | |
32 | + } | |
33 | + } | |
34 | +}; | |
0 | 35 | \ No newline at end of file | ... | ... |
src/components/modal/modal.vue
... | ... | @@ -30,15 +30,15 @@ |
30 | 30 | import Icon from '../icon'; |
31 | 31 | import iButton from '../button/button.vue'; |
32 | 32 | import TransferDom from '../../directives/transfer-dom'; |
33 | - import { getScrollBarSize } from '../../utils/assist'; | |
34 | 33 | import Locale from '../../mixins/locale'; |
35 | 34 | import Emitter from '../../mixins/emitter'; |
35 | + import ScrollbarMixins from './mixins-scrollbar'; | |
36 | 36 | |
37 | 37 | const prefixCls = 'ivu-modal'; |
38 | 38 | |
39 | 39 | export default { |
40 | 40 | name: 'Modal', |
41 | - mixins: [ Locale, Emitter ], | |
41 | + mixins: [ Locale, Emitter, ScrollbarMixins ], | |
42 | 42 | components: { Icon, iButton }, |
43 | 43 | directives: { TransferDom }, |
44 | 44 | props: { |
... | ... | @@ -186,34 +186,6 @@ |
186 | 186 | } |
187 | 187 | } |
188 | 188 | }, |
189 | - checkScrollBar () { | |
190 | - let fullWindowWidth = window.innerWidth; | |
191 | - if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8 | |
192 | - const documentElementRect = document.documentElement.getBoundingClientRect(); | |
193 | - fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left); | |
194 | - } | |
195 | - this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth; | |
196 | - if (this.bodyIsOverflowing) { | |
197 | - this.scrollBarWidth = getScrollBarSize(); | |
198 | - } | |
199 | - }, | |
200 | - setScrollBar () { | |
201 | - if (this.bodyIsOverflowing && this.scrollBarWidth !== undefined) { | |
202 | - document.body.style.paddingRight = `${this.scrollBarWidth}px`; | |
203 | - } | |
204 | - }, | |
205 | - resetScrollBar () { | |
206 | - document.body.style.paddingRight = ''; | |
207 | - }, | |
208 | - addScrollEffect () { | |
209 | - this.checkScrollBar(); | |
210 | - this.setScrollBar(); | |
211 | - document.body.style.overflow = 'hidden'; | |
212 | - }, | |
213 | - removeScrollEffect() { | |
214 | - document.body.style.overflow = ''; | |
215 | - this.resetScrollBar(); | |
216 | - }, | |
217 | 189 | animationFinish() { |
218 | 190 | this.$emit('on-hidden'); |
219 | 191 | } | ... | ... |
src/components/spin/index.js
1 | -import Spin from './spin.vue'; | |
1 | +import Spin from './spin.js'; | |
2 | + | |
3 | +let spinInstance; | |
4 | + | |
5 | +function getSpinInstance (render = undefined) { | |
6 | + spinInstance = spinInstance || Spin.newInstance({ | |
7 | + render: render | |
8 | + }); | |
9 | + | |
10 | + return spinInstance; | |
11 | +} | |
12 | + | |
13 | +function loading (options) { | |
14 | + const render = ('render' in options) ? options.render : undefined; | |
15 | + let instance = getSpinInstance(render); | |
16 | + | |
17 | + instance.show(options); | |
18 | +} | |
19 | + | |
20 | +Spin.show = function (props = {}) { | |
21 | + return loading(props); | |
22 | +}; | |
23 | +Spin.hide = function () { | |
24 | + if (!spinInstance) return false; | |
25 | + | |
26 | + const instance = getSpinInstance(); | |
27 | + | |
28 | + instance.remove(() => { | |
29 | + spinInstance = null; | |
30 | + }); | |
31 | +}; | |
32 | + | |
2 | 33 | export default Spin; |
3 | 34 | \ No newline at end of file | ... | ... |
1 | +import Vue from 'vue'; | |
2 | +import Spin from './spin.vue'; | |
3 | + | |
4 | +Spin.newInstance = properties => { | |
5 | + const _props = properties || {}; | |
6 | + | |
7 | + const Instance = new Vue({ | |
8 | + data: Object.assign({}, _props, { | |
9 | + | |
10 | + }), | |
11 | + render (h) { | |
12 | + let vnode = ''; | |
13 | + if (this.render) { | |
14 | + vnode = h(Spin, { | |
15 | + props: { | |
16 | + fix: true, | |
17 | + fullscreen: true | |
18 | + } | |
19 | + }, [this.render(h)]); | |
20 | + } else { | |
21 | + vnode = h(Spin, { | |
22 | + props: { | |
23 | + size: 'large', | |
24 | + fix: true, | |
25 | + fullscreen: true | |
26 | + } | |
27 | + }); | |
28 | + } | |
29 | + return h('div', { | |
30 | + 'class': 'ivu-spin-fullscreen' | |
31 | + }, [vnode]); | |
32 | + } | |
33 | + }); | |
34 | + | |
35 | + const component = Instance.$mount(); | |
36 | + document.body.appendChild(component.$el); | |
37 | + const spin = Instance.$children[0]; | |
38 | + | |
39 | + return { | |
40 | + show () { | |
41 | + spin.visible = true; | |
42 | + }, | |
43 | + remove (cb) { | |
44 | + spin.visible = false; | |
45 | + setTimeout(function() { | |
46 | + spin.$parent.$destroy(); | |
47 | + document.body.removeChild(document.getElementsByClassName('ivu-spin-fullscreen')[0]); | |
48 | + cb(); | |
49 | + }, 500); | |
50 | + }, | |
51 | + component: spin | |
52 | + }; | |
53 | +}; | |
54 | + | |
55 | +export default Spin; | |
0 | 56 | \ No newline at end of file | ... | ... |
src/components/spin/spin.vue
1 | 1 | <template> |
2 | 2 | <transition name="fade"> |
3 | - <div :class="classes"> | |
3 | + <div :class="classes" v-if="fullscreenVisible"> | |
4 | 4 | <div :class="mainClasses"> |
5 | 5 | <span :class="dotClasses"></span> |
6 | 6 | <div :class="textClasses"><slot></slot></div> |
... | ... | @@ -10,11 +10,13 @@ |
10 | 10 | </template> |
11 | 11 | <script> |
12 | 12 | import { oneOf } from '../../utils/assist'; |
13 | + import ScrollbarMixins from '../modal/mixins-scrollbar'; | |
13 | 14 | |
14 | 15 | const prefixCls = 'ivu-spin'; |
15 | 16 | |
16 | 17 | export default { |
17 | 18 | name: 'Spin', |
19 | + mixins: [ ScrollbarMixins ], | |
18 | 20 | props: { |
19 | 21 | size: { |
20 | 22 | validator (value) { |
... | ... | @@ -24,11 +26,17 @@ |
24 | 26 | fix: { |
25 | 27 | type: Boolean, |
26 | 28 | default: false |
29 | + }, | |
30 | + fullscreen: { | |
31 | + type: Boolean, | |
32 | + default: false | |
27 | 33 | } |
28 | 34 | }, |
29 | 35 | data () { |
30 | 36 | return { |
31 | - showText: false | |
37 | + showText: false, | |
38 | + // used for $Spin | |
39 | + visible: false | |
32 | 40 | }; |
33 | 41 | }, |
34 | 42 | computed: { |
... | ... | @@ -39,6 +47,7 @@ |
39 | 47 | [`${prefixCls}-${this.size}`]: !!this.size, |
40 | 48 | [`${prefixCls}-fix`]: this.fix, |
41 | 49 | [`${prefixCls}-show-text`]: this.showText, |
50 | + [`${prefixCls}-fullscreen`]: this.fullscreen | |
42 | 51 | } |
43 | 52 | ]; |
44 | 53 | }, |
... | ... | @@ -50,6 +59,22 @@ |
50 | 59 | }, |
51 | 60 | textClasses () { |
52 | 61 | return `${prefixCls}-text`; |
62 | + }, | |
63 | + fullscreenVisible () { | |
64 | + if (this.fullscreen) { | |
65 | + return this.visible; | |
66 | + } else { | |
67 | + return true; | |
68 | + } | |
69 | + } | |
70 | + }, | |
71 | + watch: { | |
72 | + visible (val) { | |
73 | + if (val) { | |
74 | + this.addScrollEffect(); | |
75 | + } else { | |
76 | + this.removeScrollEffect(); | |
77 | + } | |
53 | 78 | } |
54 | 79 | }, |
55 | 80 | mounted () { | ... | ... |
src/index.js
src/styles/components/spin.less