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,6 +181,8 @@ | ||
181 | </div> | 181 | </div> |
182 | <br> | 182 | <br> |
183 | 切换显示状态:<i-switch @on-change="spinShow = !spinShow"></i-switch> | 183 | 切换显示状态:<i-switch @on-change="spinShow = !spinShow"></i-switch> |
184 | + <Button @click="show">show</Button> | ||
185 | + <Button @click="hide">hide</Button> | ||
184 | </div> | 186 | </div> |
185 | </template> | 187 | </template> |
186 | <script> | 188 | <script> |
@@ -189,6 +191,29 @@ | @@ -189,6 +191,29 @@ | ||
189 | return { | 191 | return { |
190 | spinShow: true | 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 | </script> | 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 | \ No newline at end of file | 35 | \ No newline at end of file |
src/components/modal/modal.vue
@@ -30,15 +30,15 @@ | @@ -30,15 +30,15 @@ | ||
30 | import Icon from '../icon'; | 30 | import Icon from '../icon'; |
31 | import iButton from '../button/button.vue'; | 31 | import iButton from '../button/button.vue'; |
32 | import TransferDom from '../../directives/transfer-dom'; | 32 | import TransferDom from '../../directives/transfer-dom'; |
33 | - import { getScrollBarSize } from '../../utils/assist'; | ||
34 | import Locale from '../../mixins/locale'; | 33 | import Locale from '../../mixins/locale'; |
35 | import Emitter from '../../mixins/emitter'; | 34 | import Emitter from '../../mixins/emitter'; |
35 | + import ScrollbarMixins from './mixins-scrollbar'; | ||
36 | 36 | ||
37 | const prefixCls = 'ivu-modal'; | 37 | const prefixCls = 'ivu-modal'; |
38 | 38 | ||
39 | export default { | 39 | export default { |
40 | name: 'Modal', | 40 | name: 'Modal', |
41 | - mixins: [ Locale, Emitter ], | 41 | + mixins: [ Locale, Emitter, ScrollbarMixins ], |
42 | components: { Icon, iButton }, | 42 | components: { Icon, iButton }, |
43 | directives: { TransferDom }, | 43 | directives: { TransferDom }, |
44 | props: { | 44 | props: { |
@@ -186,34 +186,6 @@ | @@ -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 | animationFinish() { | 189 | animationFinish() { |
218 | this.$emit('on-hidden'); | 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 | export default Spin; | 33 | export default Spin; |
3 | \ No newline at end of file | 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 | \ No newline at end of file | 56 | \ No newline at end of file |
src/components/spin/spin.vue
1 | <template> | 1 | <template> |
2 | <transition name="fade"> | 2 | <transition name="fade"> |
3 | - <div :class="classes"> | 3 | + <div :class="classes" v-if="fullscreenVisible"> |
4 | <div :class="mainClasses"> | 4 | <div :class="mainClasses"> |
5 | <span :class="dotClasses"></span> | 5 | <span :class="dotClasses"></span> |
6 | <div :class="textClasses"><slot></slot></div> | 6 | <div :class="textClasses"><slot></slot></div> |
@@ -10,11 +10,13 @@ | @@ -10,11 +10,13 @@ | ||
10 | </template> | 10 | </template> |
11 | <script> | 11 | <script> |
12 | import { oneOf } from '../../utils/assist'; | 12 | import { oneOf } from '../../utils/assist'; |
13 | + import ScrollbarMixins from '../modal/mixins-scrollbar'; | ||
13 | 14 | ||
14 | const prefixCls = 'ivu-spin'; | 15 | const prefixCls = 'ivu-spin'; |
15 | 16 | ||
16 | export default { | 17 | export default { |
17 | name: 'Spin', | 18 | name: 'Spin', |
19 | + mixins: [ ScrollbarMixins ], | ||
18 | props: { | 20 | props: { |
19 | size: { | 21 | size: { |
20 | validator (value) { | 22 | validator (value) { |
@@ -24,11 +26,17 @@ | @@ -24,11 +26,17 @@ | ||
24 | fix: { | 26 | fix: { |
25 | type: Boolean, | 27 | type: Boolean, |
26 | default: false | 28 | default: false |
29 | + }, | ||
30 | + fullscreen: { | ||
31 | + type: Boolean, | ||
32 | + default: false | ||
27 | } | 33 | } |
28 | }, | 34 | }, |
29 | data () { | 35 | data () { |
30 | return { | 36 | return { |
31 | - showText: false | 37 | + showText: false, |
38 | + // used for $Spin | ||
39 | + visible: false | ||
32 | }; | 40 | }; |
33 | }, | 41 | }, |
34 | computed: { | 42 | computed: { |
@@ -39,6 +47,7 @@ | @@ -39,6 +47,7 @@ | ||
39 | [`${prefixCls}-${this.size}`]: !!this.size, | 47 | [`${prefixCls}-${this.size}`]: !!this.size, |
40 | [`${prefixCls}-fix`]: this.fix, | 48 | [`${prefixCls}-fix`]: this.fix, |
41 | [`${prefixCls}-show-text`]: this.showText, | 49 | [`${prefixCls}-show-text`]: this.showText, |
50 | + [`${prefixCls}-fullscreen`]: this.fullscreen | ||
42 | } | 51 | } |
43 | ]; | 52 | ]; |
44 | }, | 53 | }, |
@@ -50,6 +59,22 @@ | @@ -50,6 +59,22 @@ | ||
50 | }, | 59 | }, |
51 | textClasses () { | 60 | textClasses () { |
52 | return `${prefixCls}-text`; | 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 | mounted () { | 80 | mounted () { |
src/index.js
@@ -139,6 +139,7 @@ const install = function (Vue, opts = {}) { | @@ -139,6 +139,7 @@ const install = function (Vue, opts = {}) { | ||
139 | Vue.prototype.$Message = Message; | 139 | Vue.prototype.$Message = Message; |
140 | Vue.prototype.$Modal = Modal; | 140 | Vue.prototype.$Modal = Modal; |
141 | Vue.prototype.$Notice = Notice; | 141 | Vue.prototype.$Notice = Notice; |
142 | + Vue.prototype.$Spin = Spin; | ||
142 | }; | 143 | }; |
143 | 144 | ||
144 | // auto install | 145 | // auto install |
src/styles/components/spin.less
@@ -33,6 +33,9 @@ | @@ -33,6 +33,9 @@ | ||
33 | .square(100%); | 33 | .square(100%); |
34 | background-color: rgba(255,255,255,.9); | 34 | background-color: rgba(255,255,255,.9); |
35 | } | 35 | } |
36 | + &-fullscreen{ | ||
37 | + z-index: @zindex-spin-fullscreen; | ||
38 | + } | ||
36 | 39 | ||
37 | &-fix &-main { | 40 | &-fix &-main { |
38 | position: absolute; | 41 | position: absolute; |
src/styles/custom.less
@@ -149,6 +149,7 @@ | @@ -149,6 +149,7 @@ | ||
149 | @zindex-tooltip : 1060; | 149 | @zindex-tooltip : 1060; |
150 | @zindex-transfer : 1060; | 150 | @zindex-transfer : 1060; |
151 | @zindex-loading-bar : 2000; | 151 | @zindex-loading-bar : 2000; |
152 | +@zindex-spin-fullscreen : 2010; | ||
152 | 153 | ||
153 | // Animation | 154 | // Animation |
154 | @animation-time : .3s; | 155 | @animation-time : .3s; |