この記事では、Vue の nextTick の機能について説明します。どのように達成するか? 、特定の参考値があり、困っている友人がそれを参照できます。お役に立てば幸いです。
nextTick は Vue のコア関数であり、nextTick は Vue の内部実装でよく使用されます。しかし、多くの初心者は nextTick の原理、さらには nextTick の機能さえ理解していません。
それでは、まず nextTick とは何かを見てみましょう。
公式ドキュメントの説明を参照してください:
次の DOM 更新サイクルが終了した後に遅延コールバックを実行します。データを変更した直後にこのメソッドを使用して、更新された DOM を取得します。
公式の例をもう一度見てください:
// 修改数据 vm.msg = 'Hello' // DOM 还没有更新 Vue.nextTick(function () { // DOM 更新了 }) // 作为一个 Promise 使用 (2.1.0 起新增,详见接下来的提示) Vue.nextTick() .then(function () { // DOM 更新了 })
2.1.0 からの新機能: コールバックが提供されず、Promise をサポートする環境では、Promise が返されます。 Vue には Promise ポリフィルが付属していないことに注意してください。そのため、ターゲット ブラウザが Promise をネイティブにサポートしていない場合 (つまり、なぜ私を見ているのですか)、自分でポリフィルを提供する必要があります。
ご覧のとおり、nextTick の主な機能はデータを変更し、コールバック関数を dom の更新に作用させることです。これを見て、多くの人は混乱します。データを変更した後、DOM は自動的に更新されないのはなぜですか?
これは JS のイベント ループに関連しています。オンライン チュートリアルは無数にあるため、ここでは詳しく説明しません。この記事を読み続ける前に、イベント ループを理解することをお勧めします。
実際的な例:
ページャーを備えた表があり、ページをめくるたびに最初の項目を選択する必要があります。通常の状況では、ページめくりをクリックし、バックグラウンドからデータを取得し、テーブル データを更新し、テーブル API を操作して最初の項目を選択することが必要です。
ただし、テーブルのデータは更新されていますが、最初の項目が選択されていないことがわかります。最初の項目を選択すると、データは更新されますが、DOM は更新されないためです。この時点で、DOM が更新された後、nextTick を使用してテーブル内の最初の項目の選択を操作できます。
それでは、DOM が更新された後に nextTick はコールバック関数を実行するために正確に何をするのでしょうか?
nextTick のソースコードは src/core/util/next-tick.js にあり、合計 118 行で非常に短く簡潔です。初めてソースコードを読む学生に非常に適しています。
nextTick のソース コードは主に 2 つの部分に分かれています:
1. 機能の検出
#2. 機能の検出に応じてさまざまな方法でコールバック キューを実行します能力検出この部分は実際には非常に単純です。ご存知のとおり、イベント ループはマクロ タスクとマイクロ タスクのどちらが実行されるかに関係なく、完了後の次のティックでは、ティック間で UI レンダリングが実行されます。 ただし、マクロ タスクはマイクロ タスクよりも時間がかかるため、ブラウザがサポートしている場合は、最初にマイクロ タスクを使用してください。ブラウザがマイクロタスクをサポートしていない場合は、マクロタスクを使用します。ただし、さまざまなマクロタスクの効率も異なるため、ブラウザのサポートに基づいて異なるマクロタスクを使用する必要があります。 nextTick は、能力テストに関してはこの考えに従っています。// Determine (macro) task defer implementation. // Technically setImmediate should be the ideal choice, but it's only available // in IE. The only polyfill that consistently queues the callback after all DOM // events triggered in the same loop is by using MessageChannel. /* istanbul ignore if */ // 如果浏览器不支持Promise,使用宏任务来执行nextTick回调函数队列 // 能力检测,测试浏览器是否支持原生的setImmediate(setImmediate只在IE中有效) if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { // 如果支持,宏任务( macro task)使用setImmediate macroTimerFunc = () => { setImmediate(flushCallbacks) } // 同上 } else if (typeof MessageChannel !== 'undefined' && ( isNative(MessageChannel) || // PhantomJS MessageChannel.toString() === '[object MessageChannelConstructor]' )) { const channel = new MessageChannel() const port = channel.port2 channel.port1.onmessage = flushCallbacks macroTimerFunc = () => { port.postMessage(1) } } else { /* istanbul ignore next */ // 都不支持的情况下,使用setTimeout macroTimerFunc = () => { setTimeout(flushCallbacks, 0) } }
// 回调函数队列 const callbacks = [] // 异步锁 let pending = false // 执行回调函数 function flushCallbacks () { // 重置异步锁 pending = false // 防止出现nextTick中包含nextTick时出现问题,在执行回调函数队列前,提前复制备份,清空回调函数队列 const copies = callbacks.slice(0) callbacks.length = 0 // 执行回调函数队列 for (let i = 0; i < copies.length; i++) { copies[i]() } } ... // 我们调用的nextTick函数 export function nextTick (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 if (useMacroTask) { macroTimerFunc() } else { microTimerFunc() } } // $flow-disable-line // 2.1.0新增,如果没有提供回调,并且支持Promise,返回一个Promise if (!cb && typeof Promise !== 'undefined') { return new Promise(resolve => { _resolve = resolve }) } }
let callbacks = [] let pending = false function nextTick (cb) { callbacks.push(cb) if (!pending) { pending = true setTimeout(flushCallback, 0) } } function flushCallback () { pending = false let copies = callbacks.slice() callbacks.length = 0 copies.forEach(copy => { copy() }) }
以上がVue の nextTick にはどのような機能がありますか? nextTickの簡単な実装の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。