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