Dieser Artikel stellt hauptsächlich ein einfaches Verständnis der nextTick-Methode in Vue vor. Jetzt werde ich es mit Ihnen teilen und Ihnen eine Referenz geben.
Der nextTick in Vue beinhaltet die asynchrone Aktualisierung des DOM in Vue. Es fühlt sich sehr interessant an und ich habe speziell davon erfahren. Der Quellcode von nextTick beinhaltet viel Wissen, von dem ich viele nicht ganz verstehe. Lassen Sie uns nextTick basierend auf einigen meiner eigenen Erkenntnisse vorstellen.
1. Beispiel
Nehmen wir zunächst ein Beispiel, um mehr über DOM-Updates in Vue und die Rolle von nextTick zu erfahren.
Vorlage
<p class="app"> <p ref="msgp">{{msg}}</p> <p v-if="msg1">Message got outside $nextTick: {{msg1}}</p> <p v-if="msg2">Message got inside $nextTick: {{msg2}}</p> <p v-if="msg3">Message got outside $nextTick: {{msg3}}</p> <button @click="changeMsg"> Change the Message </button> </p>
Vue-Instanz
new Vue({ el: '.app', data: { msg: 'Hello Vue.', msg1: '', msg2: '', msg3: '' }, methods: { changeMsg() { this.msg = "Hello world." this.msg1 = this.$refs.msgp.innerHTML this.$nextTick(() => { this.msg2 = this.$refs.msgp.innerHTML }) this.msg3 = this.$refs.msgp.innerHTML } } })
Vor dem Klicken
Nach dem Klicken
Wie aus dem Bild ersichtlich ist: Der von msg1 und msg3 angezeigte Inhalt liegt vor der Transformation, während der von msg2 angezeigte Inhalt nach der Transformation liegt. Der Hauptgrund dafür ist, dass DOM-Updates in Vue asynchron sind (ausführliche Erklärung unten).
2. Anwendungsszenarien
Lernen wir mehr über die wichtigsten Anwendungsszenarien und Gründe von nextTick.
DOM-Operationen, die in der Hook-Funktion „created()“ des Vue-Lebenszyklus ausgeführt werden, müssen in der Rückruffunktion von Vue.nextTick() platziert werden.
Tatsächlich, wenn die Hook-Funktion „created()“ verwendet wird wird ausgeführt, das DOM Es wurde kein Rendern durchgeführt und die DOM-Operation ist zu diesem Zeitpunkt vergebens. Daher muss der js-Code für die DOM-Operation in die Rückruffunktion von Vue.nextTick() eingefügt werden. Dies entspricht der Hook-Funktion mount(), da das gesamte DOM-Mounting und -Rendering abgeschlossen ist, wenn die Hook-Funktion ausgeführt wird. Zu diesem Zeitpunkt treten keine Probleme bei der Ausführung von DOM-Vorgängen in der Hook-Funktion auf.
Wenn eine Operation ausgeführt werden muss, nachdem sich die Daten geändert haben, und diese Operation die Verwendung einer DOM-Struktur erfordert, die sich ändert, wenn sich die Daten ändern, sollte diese Operation in die Rückruffunktion von Vue.nextTick() eingefügt werden .
Der konkrete Grund wird in der offiziellen Dokumentation von Vue ausführlich erläutert:
Vue führt DOM-Updates asynchron durch. Immer wenn eine Datenänderung beobachtet wird, öffnet Vue eine Warteschlange und puffert alle Datenänderungen, die in derselben Ereignisschleife auftreten. Wenn derselbe Watcher mehrmals ausgelöst wird, wird er nur einmal in die Warteschlange verschoben. Diese Deduplizierung während der Pufferung ist wichtig, um unnötige Berechnungen und DOM-Operationen zu vermeiden. Beim nächsten „Tick“ der Ereignisschleife leert Vue dann die Warteschlange und führt die eigentliche (deduplizierte) Arbeit aus. Vue versucht intern, natives Promise.then und MessageChannel für asynchrone Warteschlangen zu verwenden. Wenn die Ausführungsumgebung dies nicht unterstützt, wird stattdessen setTimeout(fn, 0) verwendet.
Wenn Sie beispielsweise vm.someData = 'new value' festlegen, wird die Komponente nicht sofort erneut gerendert. Wenn die Warteschlange geleert wird, wird die Komponente beim nächsten „Tick“ aktualisiert, wenn die Ereignisschleifenwarteschlange gelöscht wird. In den meisten Fällen müssen wir uns um diesen Vorgang nicht kümmern, aber wenn Sie nach der Aktualisierung des DOM-Status etwas tun möchten, kann dies etwas schwierig sein. Während Vue.js Entwickler im Allgemeinen dazu ermutigt, „datengesteuert“ zu denken und das DOM nicht direkt zu berühren, gibt es Zeiten, in denen wir das wirklich tun müssen. Um zu warten, bis Vue die Aktualisierung des DOM nach den Datenänderungen abgeschlossen hat, können Sie Vue.nextTick(callback) unmittelbar nach den Datenänderungen verwenden. Diese Rückruffunktion wird aufgerufen, nachdem die DOM-Aktualisierung abgeschlossen ist.
3. Kurze Analyse des nextTick-Quellcodes
Funktion
Vue.nextTick wird verwendet, um die Ausführung von a zu verzögern Codestück. Es akzeptiert zwei Parameter (Callback-Funktion und den Kontext, in dem die Callback-Funktion ausgeführt wird). Wenn keine Callback-Funktion bereitgestellt wird, wird ein Promise-Objekt zurückgegeben.
Quellcode
/** * Defer a task to execute it asynchronously. */ export const nextTick = (function () { const callbacks = [] let pending = false let timerFunc function nextTickHandler () { pending = false const copies = callbacks.slice(0) callbacks.length = 0 for (let i = 0; i < copies.length; i++) { copies[i]() } } // the nextTick behavior leverages the microtask queue, which can be accessed // via either native Promise.then or MutationObserver. // MutationObserver has wider support, however it is seriously bugged in // UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It // completely stops working after triggering a few times... so, if native // Promise is available, we will use it: /* istanbul ignore if */ if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve() var logError = err => { console.error(err) } timerFunc = () => { p.then(nextTickHandler).catch(logError) // in problematic UIWebViews, Promise.then doesn't completely break, but // it can get stuck in a weird state where callbacks are pushed into the // microtask queue but the queue isn't being flushed, until the browser // needs to do some other work, e.g. handle a timer. Therefore we can // "force" the microtask queue to be flushed by adding an empty timer. if (isIOS) setTimeout(noop) } } else if (!isIE && typeof MutationObserver !== 'undefined' && ( isNative(MutationObserver) || // PhantomJS and iOS 7.x MutationObserver.toString() === '[object MutationObserverConstructor]' )) { // use MutationObserver where native Promise is not available, // e.g. PhantomJS, iOS7, Android 4.4 var counter = 1 var observer = new MutationObserver(nextTickHandler) var textNode = document.createTextNode(String(counter)) observer.observe(textNode, { characterData: true }) timerFunc = () => { counter = (counter + 1) % 2 textNode.data = String(counter) } } else { // fallback to setTimeout /* istanbul ignore next */ timerFunc = () => { setTimeout(nextTickHandler, 0) } } return function queueNextTick (cb?: Function, ctx?: Object) { let _resolve callbacks.push(() => { if (cb) { try { cb.call(ctx) } catch (e) { handleError(e, ctx, 'nextTick') } } else if (_resolve) { _resolve(ctx) } }) if (!pending) { pending = true timerFunc() } if (!cb && typeof Promise !== 'undefined') { return new Promise((resolve, reject) => { _resolve = resolve }) } } })()
Lassen Sie uns zunächst die drei wichtigen Variablen verstehen, die in nextTick definiert sind.
Rückrufe: werden zum Speichern aller Rückruffunktionen verwendet, die ausgeführt werden müssen
ausstehend: werden verwendet, um zu markieren, ob die Rückruffunktion ausgeführt wird
timerFunc: wird verwendet, um die Ausführung der Callback-Funktion auszulösen
Als nächstes erfahren Sie mehr über die Funktion nextTickHandler().
function nextTickHandler () { pending = false const copies = callbacks.slice(0) callbacks.length = 0 for (let i = 0; i < copies.length; i++) { copies[i]() } }
Diese Funktion wird verwendet, um alle in Callbacks gespeicherten Callback-Funktionen auszuführen.
Der nächste Schritt besteht darin, timerFunc die Trigger-Methode zuzuweisen.
Bestimmen Sie zunächst, ob Promise nativ unterstützt wird.
Andernfalls, wenn MutationObserver unterstützt wird, instanziieren Sie Änderungen im Textknoten. Wenn alle Callback-Funktionen ausgeführt werden.
Wenn keines von beiden unterstützt wird, verwenden Sie setTimeout, um die Verzögerung auf 0 zu setzen.
Schließlich ist die queueNextTick-Funktion. Da es sich bei nextTick um eine unmittelbare Funktion handelt, handelt es sich bei der queueNextTick-Funktion um eine zurückgegebene Funktion, die vom Benutzer übergebene Parameter akzeptiert und zum Speichern von Rückruffunktionen in Rückrufen verwendet wird.
Das obige Bild zeigt den gesamten Ausführungsprozess. Der Schlüssel liegt in timeFunc(), das die Rolle der verzögerten Ausführung spielt.
Aus der obigen Einführung können wir erkennen, dass es drei Implementierungsmethoden von timeFunc() gibt.
Versprechen
MutationObserver
setTimeout
其中Promise和setTimeout很好理解,是一个异步任务,会在同步任务以及更新DOM的异步任务之后回调具体函数。
下面着重介绍一下MutationObserver。
MutationObserver是HTML5中的新API,是个用来监视DOM变动的接口。他能监听一个DOM对象上发生的子节点删除、属性修改、文本内容修改等等。
调用过程很简单,但是有点不太寻常:你需要先给他绑回调:
var mo = new MutationObserver(callback)
通过给MutationObserver的构造函数传入一个回调,能得到一个MutationObserver实例,这个回调就会在MutationObserver实例监听到变动时触发。
这个时候你只是给MutationObserver实例绑定好了回调,他具体监听哪个DOM、监听节点删除还是监听属性修改,还没有设置。而调用他的observer方法就可以完成这一步:
var domTarget = 你想要监听的dom节点 mo.observe(domTarget, { characterData: true //说明监听文本内容的修改。 })
在nextTick中 MutationObserver的作用就如上图所示。在监听到DOM更新后,调用回调函数。
其实使用 MutationObserver的原因就是 nextTick想要一个异步API,用来在当前的同步代码执行完毕后,执行我想执行的异步回调,包括Promise和 setTimeout都是基于这个原因。其中深入还涉及到microtask等内容,暂时不理解,就不深入介绍了。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
Das obige ist der detaillierte Inhalt vonDetaillierte Einführung in die nextTick-Methode in Vue. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!