瀏覽代碼

Skip transitions when visibility does not change

Simone Todaro 5 年之前
父節點
當前提交
028ea0d015
共有 4 個文件被更改,包括 112 次插入10 次删除
  1. 0 0
      dist/alpine.js
  2. 0 0
      dist/alpine.js.map
  3. 14 10
      src/directives/show.js
  4. 98 0
      test/transition.spec.js

文件差異過大導致無法顯示
+ 0 - 0
dist/alpine.js


文件差異過大導致無法顯示
+ 0 - 0
dist/alpine.js.map


+ 14 - 10
src/directives/show.js

@@ -2,16 +2,20 @@ import { transitionIn, transitionOut } from '../utils'
 
 export function handleShowDirective(el, value, initialUpdate = false) {
     if (! value) {
-        transitionOut(el, () => {
-            el.style.display = 'none'
-        }, initialUpdate)
+        if ( el.style.display !== 'none' ) {
+            transitionOut(el, () => {
+                el.style.display = 'none'
+            }, initialUpdate)
+        }
     } else {
-        transitionIn(el, () => {
-            if (el.style.length === 1 && el.style.display !== '') {
-                el.removeAttribute('style')
-            } else {
-                el.style.removeProperty('display')
-            }
-        }, initialUpdate)
+        if ( el.style.display !== '' ) {
+            transitionIn(el, () => {
+                if (el.style.length === 1) {
+                    el.removeAttribute('style')
+                } else {
+                    el.style.removeProperty('display')
+                }
+            }, initialUpdate)
+        }
     }
 }

+ 98 - 0
test/transition.spec.js

@@ -202,3 +202,101 @@ test('original class attribute classes are preserved after transition finishes',
         }, 10)
     )
 })
+
+test('transition in not called when item is already visible', async () => {
+    // Hijack "requestAnimationFrame" for finer-tuned control in this test.
+    var frameStack = []
+
+    jest.spyOn(window, 'requestAnimationFrame').mockImplementation((callback) => {
+        frameStack.push(callback)
+    });
+
+    // Hijack "getComputeStyle" because js-dom is weird with it.
+    // (hardcoding 10ms transition time for later assertions)
+    jest.spyOn(window, 'getComputedStyle').mockImplementation(el => {
+        return { transitionDuration: '.01s' }
+    });
+
+    document.body.innerHTML = `
+        <div x-data="{ show: true }">
+            <button x-on:click="show = true"></button>
+
+            <span
+                x-show="show"
+                x-transition:enter="enter"
+                x-transition:enter-start="enter-start"
+                x-transition:enter-end="enter-end"
+            ></span>
+        </div>
+    `
+
+    Alpine.start()
+
+    expect(document.querySelector('span').getAttribute('style')).toEqual(null)
+
+    document.querySelector('button').click()
+
+    // Wait out the intial Alpine refresh debounce.
+    await new Promise((resolve) =>
+        setTimeout(() => {
+            resolve();
+        }, 5)
+    )
+
+    // No animation queued
+    expect(frameStack.pop()).toEqual(undefined)
+
+    expect(document.querySelector('span').classList.contains('enter')).toEqual(false)
+    expect(document.querySelector('span').classList.contains('enter-start')).toEqual(false)
+    expect(document.querySelector('span').classList.contains('enter-end')).toEqual(false)
+    expect(document.querySelector('span').getAttribute('style')).toEqual(null)
+})
+
+test('transition out not called when item is already hidden', async () => {
+    // Hijack "requestAnimationFrame" for finer-tuned control in this test.
+    var frameStack = []
+
+    jest.spyOn(window, 'requestAnimationFrame').mockImplementation((callback) => {
+        frameStack.push(callback)
+    });
+
+    // Hijack "getComputeStyle" because js-dom is weird with it.
+    // (hardcoding 10ms transition time for later assertions)
+    jest.spyOn(window, 'getComputedStyle').mockImplementation(el => {
+        return { transitionDuration: '.01s' }
+    });
+
+    document.body.innerHTML = `
+        <div x-data="{ show: false }">
+            <button x-on:click="show = false"></button>
+
+            <span
+                x-show="show"
+                x-transition:leave="leave"
+                x-transition:leave-start="leave-start"
+                x-transition:leave-end="leave-end"
+            ></span>
+        </div>
+    `
+
+    Alpine.start()
+
+    expect(document.querySelector('span').getAttribute('style')).toEqual('display: none;')
+
+    document.querySelector('button').click()
+
+    // Wait out the intial Alpine refresh debounce.
+    await new Promise((resolve) =>
+        setTimeout(() => {
+            resolve();
+        }, 5)
+    )
+
+    // No animation queued
+    expect(frameStack.pop()).toEqual(undefined)
+
+    expect(document.querySelector('span').classList.contains('leave')).toEqual(false)
+    expect(document.querySelector('span').classList.contains('leave-start')).toEqual(false)
+    expect(document.querySelector('span').classList.contains('leave-end')).toEqual(false)
+    expect(document.querySelector('span').getAttribute('style')).toEqual('display: none;')
+})

部分文件因文件數量過多而無法顯示