Loading: add fading animations

pull/2394/head
Leopoldthecoder 2017-01-13 15:31:05 +08:00
parent 9f94a28f43
commit 813de47354
5 changed files with 78 additions and 39 deletions

View File

@ -36,37 +36,42 @@ exports.install = Vue => {
}); });
} else { } else {
if (el.domVisible) { if (el.domVisible) {
el.mask.style.display = 'none'; const destroyElement = function() {
el.domVisible = false; el.mask.removeEventListener('transitionend', destroyElement);
el.domVisible = false;
if (binding.modifiers.fullscreen && el.originalOverflow !== 'hidden') { if (binding.modifiers.fullscreen && el.originalOverflow !== 'hidden') {
document.body.style.overflow = el.originalOverflow; document.body.style.overflow = el.originalOverflow;
} }
if (binding.modifiers.fullscreen || binding.modifiers.body) { if (binding.modifiers.fullscreen || binding.modifiers.body) {
document.body.style.position = el.originalPosition; document.body.style.position = el.originalPosition;
} else { } else {
el.style.position = el.originalPosition; el.style.position = el.originalPosition;
} }
};
el.mask.addEventListener('transitionend', destroyElement);
el.instance.visible = false;
} }
} }
}; };
let insertDom = (parent, directive, binding) => { let insertDom = (parent, el, binding) => {
if (!directive.domVisible) { if (!el.domVisible) {
Object.keys(directive.maskStyle).forEach(property => { Object.keys(el.maskStyle).forEach(property => {
directive.mask.style[property] = directive.maskStyle[property]; el.mask.style[property] = el.maskStyle[property];
}); });
if (directive.originalPosition !== 'absolute') { if (el.originalPosition !== 'absolute') {
parent.style.position = 'relative'; parent.style.position = 'relative';
} }
if (binding.modifiers.fullscreen && binding.modifiers.lock) { if (binding.modifiers.fullscreen && binding.modifiers.lock) {
parent.style.overflow = 'hidden'; parent.style.overflow = 'hidden';
} }
directive.mask.style.display = 'block'; el.domVisible = true;
directive.domVisible = true;
parent.appendChild(directive.mask); parent.appendChild(el.mask);
directive.domInserted = true; Vue.nextTick(() => {
el.instance.visible = true;
});
el.domInserted = true;
} }
}; };
@ -79,6 +84,7 @@ exports.install = Vue => {
fullscreen: !!binding.modifiers.fullscreen fullscreen: !!binding.modifiers.fullscreen
} }
}); });
el.instance = mask;
el.mask = mask.$el; el.mask = mask.$el;
el.maskStyle = {}; el.maskStyle = {};

View File

@ -17,6 +17,14 @@ let fullscreenLoading;
LoadingConstructor.prototype.originalPosition = ''; LoadingConstructor.prototype.originalPosition = '';
LoadingConstructor.prototype.originalOverflow = ''; LoadingConstructor.prototype.originalOverflow = '';
const destroyElement = function() {
this.$el.removeEventListener('transitionend', destroyElement);
this.$el &&
this.$el.parentNode &&
this.$el.parentNode.removeChild(this.$el);
this.$destroy();
};
LoadingConstructor.prototype.close = function() { LoadingConstructor.prototype.close = function() {
if (this.fullscreen && this.originalOverflow !== 'hidden') { if (this.fullscreen && this.originalOverflow !== 'hidden') {
document.body.style.overflow = this.originalOverflow; document.body.style.overflow = this.originalOverflow;
@ -29,10 +37,8 @@ LoadingConstructor.prototype.close = function() {
if (this.fullscreen) { if (this.fullscreen) {
fullscreenLoading = undefined; fullscreenLoading = undefined;
} }
this.$el && this.$el.addEventListener('transitionend', destroyElement.bind(this));
this.$el.parentNode && this.visible = false;
this.$el.parentNode.removeChild(this.$el);
this.$destroy();
}; };
const addStyle = (options, parent, instance) => { const addStyle = (options, parent, instance) => {
@ -90,6 +96,9 @@ const Loading = (options = {}) => {
parent.style.overflow = 'hidden'; parent.style.overflow = 'hidden';
} }
parent.appendChild(instance.$el); parent.appendChild(instance.$el);
Vue.nextTick(() => {
instance.visible = true;
});
if (options.fullscreen) { if (options.fullscreen) {
fullscreenLoading = instance; fullscreenLoading = instance;
} }

View File

@ -1,12 +1,17 @@
<template> <template>
<div class="el-loading-mask" :class="[customClass, { 'is-fullscreen': fullscreen }]"> <transition name="el-loading-fade">
<div class="el-loading-spinner"> <div
<svg class="circular" viewBox="25 25 50 50"> v-show="visible"
<circle class="path" cx="50" cy="50" r="20" fill="none"/> class="el-loading-mask"
</svg> :class="[customClass, { 'is-fullscreen': fullscreen }]">
<p v-if="text" class="el-loading-text">{{ text }}</p> <div class="el-loading-spinner">
<svg class="circular" viewBox="25 25 50 50">
<circle class="path" cx="50" cy="50" r="20" fill="none"/>
</svg>
<p v-if="text" class="el-loading-text">{{ text }}</p>
</div>
</div> </div>
</div> </transition>
</template> </template>
<script> <script>
@ -15,6 +20,7 @@
return { return {
text: null, text: null,
fullscreen: true, fullscreen: true,
visible: false,
customClass: '' customClass: ''
}; };
} }

View File

@ -11,6 +11,7 @@
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
transition: opacity 0.3s;
@when fullscreen { @when fullscreen {
position: fixed; position: fixed;
@ -54,6 +55,11 @@
} }
} }
.el-loading-fade-enter,
.el-loading-fade-leave-active {
opacity: 0;
}
@keyframes loading-rotate { @keyframes loading-rotate {
100% { 100% {
transform: rotate(360deg); transform: rotate(360deg);

View File

@ -7,8 +7,18 @@ describe('Loading', () => {
let vm, loadingInstance, loadingInstance2; let vm, loadingInstance, loadingInstance2;
afterEach(() => { afterEach(() => {
destroyVM(vm); destroyVM(vm);
loadingInstance && loadingInstance.close(); if (loadingInstance) {
loadingInstance2 && loadingInstance2.close(); loadingInstance.close();
loadingInstance.$el &&
loadingInstance.$el.parentNode &&
loadingInstance.$el.parentNode.removeChild(loadingInstance.$el);
}
if (loadingInstance2) {
loadingInstance2.close();
loadingInstance2.$el &&
loadingInstance2.$el.parentNode &&
loadingInstance2.$el.parentNode.removeChild(loadingInstance2.$el);
}
}); });
describe('as a directive', () => { describe('as a directive', () => {
@ -171,7 +181,7 @@ describe('Loading', () => {
it('close', () => { it('close', () => {
loadingInstance = Loading(); loadingInstance = Loading();
loadingInstance.close(); loadingInstance.close();
expect(document.querySelector('.el-loading-mask')).to.not.exist; expect(loadingInstance.visible).to.false;
}); });
it('target', () => { it('target', () => {
@ -216,11 +226,13 @@ describe('Loading', () => {
let masks = document.querySelectorAll('.el-loading-mask'); let masks = document.querySelectorAll('.el-loading-mask');
expect(masks.length).to.equal(1); expect(masks.length).to.equal(1);
loadingInstance2.close(); loadingInstance2.close();
masks = document.querySelectorAll('.el-loading-mask'); setTimeout(() => {
expect(masks.length).to.equal(0); masks = document.querySelectorAll('.el-loading-mask');
done(); expect(masks.length).to.equal(0);
}, 100); done();
}, 100); }, 350);
}, 10);
}, 10);
}); });
it('lock', () => { it('lock', () => {