ソースを参照

Defer nextTick to the next animation frame

Simone Todaro 5 年 前
コミット
80d960a1e9
2 ファイル変更40 行追加5 行削除
  1. 8 5
      src/component.js
  2. 32 0
      test/next-tick.spec.js

+ 8 - 5
src/component.js

@@ -187,11 +187,14 @@ export default class Component {
 
     executeAndClearNextTickStack(el) {
         // Skip spawns from alpine directives
-        if (el === this.$el) {
-            // Walk through the $nextTick stack and clear it as we go.
-            while (this.nextTickStack.length > 0) {
-                this.nextTickStack.shift()()
-            }
+        if (el === this.$el && this.nextTickStack.length > 0) {
+            // We run the tick stack after the next frame to allow any
+            // running transitions to pass the initial show stage.
+            requestAnimationFrame(() => {
+                while (this.nextTickStack.length > 0) {
+                    this.nextTickStack.shift()()
+                }
+            })
         }
     }
 

+ 32 - 0
test/next-tick.spec.js

@@ -44,3 +44,35 @@ test('nextTick wait for x-for to finish rendering', async () => {
 
     await wait(() => { expect(document.querySelector('p').innerText).toEqual(3) })
 })
+
+test('$nextTick works with transition', async () => {
+    jest.spyOn(window, 'requestAnimationFrame').mockImplementation((callback) => {
+        setTimeout(callback, 0)
+    });
+
+    document.body.innerHTML = `
+        <div x-data="{show: false, foo: '---'}">
+            <div id="A"
+                x-show="show"
+                x-transition:enter="enter"
+                x-transition:enter-start="enter-start"
+                x-transition:enter-end="enter-end">
+                <input x-ref="foo">
+            </div>
+            <span x-text="foo"></span>
+            <button x-on:click="show = true; $nextTick(() => {foo = document.querySelector('#A').getAttribute('style')})"></button>
+        </div>
+    `
+
+    Alpine.start()
+
+    await wait(() => expect(document.querySelector('#A').getAttribute('style')).toEqual('display: none;'))
+
+    document.querySelector('button').click()
+
+    await wait(() => expect(document.querySelector('#A').getAttribute('style')).toEqual(null))
+
+    // Next tick should run after we show the element so the style property should be null
+    // We stash it in a variable so we can test it without worring about timing issues
+    expect(document.querySelector('span').innerText).toEqual(null)
+})