1
0
Эх сурвалжийг харах

Add $nextTick magic function

Caleb Porzio 5 жил өмнө
parent
commit
5757842927

+ 42 - 3
README.md

@@ -8,13 +8,13 @@ You get to keep your DOM, and sprinkle in behavior as you see fit.
 
 Think of it like [Tailwind](https://tailwindcss.com/) for JavaScript.
 
-> Note: This tool's syntax is almost entirely borrowed from [Vue.js](https://vuejs.org/) (and by extension [Angular](https://angularjs.org/)). I am forever grateful for the gift they are to the web.
+> Note: This tool's syntax is almost entirely borrowed from [Vue](https://vuejs.org/) (and by extension [Angular](https://angularjs.org/)). I am forever grateful for the gift they are to the web.
 
 ## Install
 
 **From CDN:** Add the following script to the end of your `<head>` section.
 ```html
-<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v1.3.1/dist/alpine.js" defer></script>
+<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v1.4.0/dist/alpine.js" defer></script>
 ```
 
 That's it. It will initialize itself.
@@ -101,7 +101,14 @@ There are 12 directives available to you:
 | [`x-transition`](#x-transition) |
 | [`x-cloak`](#x-cloak) |
 
-Here's how they each work:
+And 2 magic objects/functions:
+
+| Magic object/function
+| --- |
+| `$refs`(#refs) |
+| `$nextTick`(#next-tick) |
+
+### Directives
 
 ---
 
@@ -354,3 +361,35 @@ These behave exactly like VueJs's transition directives, except they have differ
     [x-cloak] { display: none; }
 </style>
 ```
+
+### Magic Objects/Functions
+
+---
+
+### `$refs`
+**Example:**
+```html
+<span x-ref="foo">
+
+<button x-on:click="$refs.foo.innerText = 'bar'">
+```
+
+`$refs` is a magic object that can be used to retreive DOM elements marked with `x-ref` inside the component. This is useful when you need to manually manipulate DOM elements.
+
+---
+
+### `$nextTick`
+**Example:**
+```html
+<div x-data="{ fruit: 'apple' }">
+    <button
+        x-on:click="
+            fruit = 'pear';
+            $nextTick(() => { console.log($event.target.innerText) });
+        "
+        x-text="fruit"
+    >
+</div>
+```
+
+`$nextTick` is a magic function that allows you to only execute a given expression AFTER Alpine has made it's reactive DOM updates. This is useful for times you want to interact with the DOM state AFTER it's reflected any data updates you've made.

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/alpine.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/alpine.js.map


+ 1 - 1
package.json

@@ -1,7 +1,7 @@
 {
   "main": "dist/alpine.js",
   "name": "alpinejs",
-  "version": "1.3.1",
+  "version": "1.4.0",
   "repository": {
     "type": "git",
     "url": "git://github.com/alpinejs/alpine.git"

+ 30 - 0
src/component.js

@@ -4,10 +4,18 @@ export default class Component {
     constructor(el) {
         this.el = el
 
+        // For $nextTick().
+        this.tickStack = []
+        this.collectingTickCallbacks = false
+
         const rawData = saferEval(this.el.getAttribute('x-data'), {})
 
         rawData.$refs =  this.getRefsProxy()
 
+        rawData.$nextTick =  (callback) => {
+            this.delayRunByATick(callback)
+        }
+
         this.runXInit(this.el.getAttribute('x-init'), rawData)
 
         this.data = this.wrapDataInObservable(rawData)
@@ -17,6 +25,25 @@ export default class Component {
         this.listenForNewElementsToInitialize()
     }
 
+    delayRunByATick(callback) {
+        if (this.collectingTickCallbacks) {
+            this.tickStack.push(callback)
+        } else {
+            callback()
+        }
+    }
+
+    startTick() {
+        this.collectingTickCallbacks = true
+    }
+
+    clearAndEndTick() {
+        this.tickStack.forEach(callable => callable())
+        this.tickStack = []
+
+        this.collectingTickCallbacks = false
+    }
+
     runXInit(initExpression, rawData) {
         initExpression && saferEvalNoReturn(initExpression, rawData)
     }
@@ -183,8 +210,11 @@ export default class Component {
             walkSkippingNestedComponents(rootEl, callback)
 
             self.concernedData = []
+            self.clearAndEndTick()
         }
 
+        this.startTick()
+
         debounce(walkThenClearDependancyTracker, 5)(this.el, function (el) {
             getXAttrs(el).forEach(({ type, value, expression }) => {
                 if (! actionByDirectiveType[type]) return

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

@@ -0,0 +1,24 @@
+import Alpine from 'alpinejs'
+import { wait } from '@testing-library/dom'
+
+global.MutationObserver = class {
+    observe() {}
+}
+
+test('$nextTick', async () => {
+    document.body.innerHTML = `
+        <div x-data="{foo: 'bar'}">
+            <span x-text="foo" x-ref="span"></span>
+
+            <button x-on:click="foo = 'baz'; $nextTick(() => {$refs.span.innerText = 'bob'})"></button>
+        </div>
+    `
+
+    Alpine.start()
+
+    expect(document.querySelector('span').innerText).toEqual('bar')
+
+    document.querySelector('button').click()
+
+    await wait(() => { expect(document.querySelector('span').innerText).toEqual('bob') })
+})

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно