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; |