Przeglądaj źródła

Loading: add fading animations

Leopoldthecoder 8 lat temu
rodzic
commit
813de47354

+ 26 - 20
packages/loading/src/directive.js

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

+ 13 - 4
packages/loading/src/index.js

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

+ 13 - 7
packages/loading/src/loading.vue

@@ -1,12 +1,17 @@
 <template>
-  <div class="el-loading-mask" :class="[customClass, { 'is-fullscreen': fullscreen }]">
-    <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>
+  <transition name="el-loading-fade">
+    <div
+      v-show="visible"
+      class="el-loading-mask"
+      :class="[customClass, { 'is-fullscreen': fullscreen }]">
+      <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>
+  </transition>
 </template>
 
 <script>
@@ -15,6 +20,7 @@
       return {
         text: null,
         fullscreen: true,
+        visible: false,
         customClass: ''
       };
     }

+ 6 - 0
packages/theme-default/src/loading.css

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

+ 20 - 8
test/unit/specs/loading.spec.js

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