ホームページ >ウェブフロントエンド >jsチュートリアル >vueデータコントロールビューのソースコードの解析
この記事では主に Vue データ コントロール ビューのソース コードの分析を紹介します。これには特定の参考値があります。必要な友達はそれを参照できます。
Vue がデータの変更とビューを更新する方法の分析。 。
はじめに
3 か月前、私はレスポンシブ データを実現する方法を分析するために vue ソース コードを読みました。最後に、データが変更された後、 Watcher の update() メソッドが呼び出されます。それでは、3 か月後に update() が何を行うかを見てみましょう (私は過去 3 か月で React-native を使用したプロジェクトを実行しましたが、それを要約するつもりはありません。簡単すぎるようです)
この記事のストーリー この方法は、ソース コードを確認するロジックに従うことです。私がチェックした vue のバージョンは、コメントを記録するためにソース コードのコピーをフォークしました。
目的
調査の方向性を明確にすることによってのみ、目標を達成することができます。まず、ターゲットの動作について説明します。データが変更された後にビューを更新するためにどのメソッドが実行されるかについて説明します。次に、この方向に向けて開始する準備をし、調査を開始します。 vue のソースコードの入り口から答えを求めます
前の結論から始めましょう
まずは復習しましょう 前の結論を見てみましょう:
vue が構築されると、Observer オブジェクトがデータ上に作成されます (ゲッターとセッターはインターセプトされます。ゲッターは依存関係の収集をトリガーし、セッターは通知をトリガーします。ウォッチを登録するときにウォッチ オブジェクトが 1 回呼び出され、ゲッターがトリガーされます。監視オブジェクトの依存関係を現在の Watcher の deps に収集します。dep の setter がトリガーされると、現在の Watcher に通知され、Watcher の update() メソッドが呼び出されます。
次に、レンダリング関連の Watcher を登録することから始めます。 .
new Watcher(vm, updateComponent, noop, null, true /* isRenderWatcher */)
mountComponent
レンダリング関連のWatcherはmountComponent()内にあり、このメソッドで呼び出されるので、このメソッドがどこにあるかを検索しましょうWeb を例にすると、 src/platforms/web/runtime/index.js と src/platforms/weex/runtime/index.js という 2 つの場所しかありません。
Vue.prototype.$mount = function ( el?: string | Element, hydrating?: boolean ): Component { el = el && inBrowser ? query(el) : undefined return mountComponent(this, el, hydrating) }$mount であることがわかります。 () メソッドは mountComponent() を呼び出します (または、vue 構築中に el フィールドを指定すると、$mount() メソッドも自動的に呼び出されます)。これは、Web と weex (weex とは何ですか? 以前に他の記事で紹介しました) レンダリング オブジェクトが異なるためです。したがって、パブリッシュ時に異なるファイルが導入され、最終的には異なる dist としてパブリッシュされる必要があります (この問題は後で vue のプロセス全体を検討することになります 以下は mountComponent メソッドです:
export function mountComponent ( vm: Component, el: ?Element, hydrating?: boolean ): Component { vm.$el = el // 放一份el到自己的属性里 if (!vm.$options.render) { // render应该经过处理了, 因为我们经常都是用template或者vue文件 // 判断是否存在render函数, 如果没有就把render函数写成空VNode来避免红错, 并报出黄错 vm.$options.render = createEmptyVNode if (process.env.NODE_ENV !== 'production') { /* istanbul ignore if */ if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') || vm.$options.el || el) { warn( 'You are using the runtime-only build of Vue where the template ' + 'compiler is not available. Either pre-compile the templates into ' + 'render functions, or use the compiler-included build.', vm ) } else { warn( 'Failed to mount component: template or render function not defined.', vm ) } } } callHook(vm, 'beforeMount') let updateComponent /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && config.performance && mark) { // 不看这里的代码了, 直接看else里的, 行为是一样的 updateComponent = () => { const name = vm._name const id = vm._uid const startTag = `vue-perf-start:${id}` const endTag = `vue-perf-end:${id}` mark(startTag) const vnode = vm._render() mark(endTag) measure(`vue ${name} render`, startTag, endTag) mark(startTag) vm._update(vnode, hydrating) mark(endTag) measure(`vue ${name} patch`, startTag, endTag) } } else { updateComponent = () => { vm._update(vm._render(), hydrating) } } // we set this to vm._watcher inside the watcher's constructor // since the watcher's initial patch may call $forceUpdate (e.g. inside child // component's mounted hook), which relies on vm._watcher being already defined // 注册一个Watcher new Watcher(vm, updateComponent, noop, null, true /* isRenderWatcher */) hydrating = false // manually mounted instance, call mounted on self // mounted is called for render-created child components in its inserted hook if (vm.$vnode == null) { vm._isMounted = true callHook(vm, 'mounted') } return vm }このコードは実際には 3 つのことだけを実行します: beforeMountフックを呼び出す
if (isRenderWatcher) { vm._watcher = this }はい、コピーしただけです。1 つは、Watcher が初めてパッチを適用するときに何かを判断するために使用されます (からコメント、それが何のためのものなのかはまだわかりません) 次に、未解決の問題が 1 つだけあります。それは、UpdateComponent が Watcher のコンストラクターの 2 番目のパラメーターとして関数を渡すことです。賢明な方なら、この updateComponent でビュー内のすべてのデータを呼び出す必要があると推測できるはずです。これにより、ビューがデータの変更に応答できるようになります。
updateComponent = () => { vm._update(vm._render(), hydrating) }
次に、vm._update() と vm._render() に移動します。 src/core/instance/render.js でそれらを見つけます。
Vue.prototype._render = function (): VNode { const vm: Component = this const { render, _parentVnode } = vm.$options // todo: render和_parentVnode的由来 // reset _rendered flag on slots for duplicate slot check if (process.env.NODE_ENV !== 'production') { for (const key in vm.$slots) { // $flow-disable-line vm.$slots[key]._rendered = false } } if (_parentVnode) { vm.$scopedSlots = _parentVnode.data.scopedSlots || emptyObject } // set parent vnode. this allows render functions to have access // to the data on the placeholder node. vm.$vnode = _parentVnode // render self let vnode try { vnode = render.call(vm._renderProxy, vm.$createElement) } catch (e) { // catch其实不需要看了, 都是做异常处理, _vnode是在vm._update的时候保存的, 也就是上次的状态或是null(init的时候给的) handleError(e, vm, `render`) // return error render result, // or previous vnode to prevent render error causing blank component /* istanbul ignore else */ if (process.env.NODE_ENV !== 'production') { if (vm.$options.renderError) { try { vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e) } catch (e) { handleError(e, vm, `renderError`) vnode = vm._vnode } } else { vnode = vm._vnode } } else { vnode = vm._vnode } } // return empty vnode in case the render function errored out if (!(vnode instanceof VNode)) { if (process.env.NODE_ENV !== 'production' && Array.isArray(vnode)) { warn( 'Multiple root nodes returned from render function. Render function ' + 'should return a single root node.', vm ) } vnode = createEmptyVNode() } // set parent vnode.parent = _parentVnode return vnode } }このメソッドは次のことを行います: VNode を生成します。現在の VM の render メソッドに基づいて (render メソッドはテンプレートまたは vue ファイルからコンパイルされる可能性があるため、render メソッドを直接記述するのが最も効率的であると推測されます) render メソッドを呼び出し、最初に renderError メソッドを呼び出し、失敗した場合は最後の vnode または null を読み取ります。
最後に VNode に戻ります
vnode = render.call(vm._renderProxy, vm.$createElement)
結論
Vue のビューのレンダリングは特別な種類の Watcher であり、関数の実行プロセスは render 関数を呼び出します (テンプレートには監視されたデータが含まれています)。そのため、テンプレート内の観察されたデータが変更されると、Watcher の update() メソッドがトリガーされてビューが再レンダリングされます。 dist
__patch__ と VNode 分析の作成プロセスとは何ですか
以上がこの記事の全内容です。その他の関連コンテンツについては、PHP 中国語 Web サイトをご覧ください。 !
関連する推奨事項:
クロスドメインルーティングの競合を解決するための vue のアイデアについて
以上がvueデータコントロールビューのソースコードの解析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。