Vue はデータ変更を操作し、ビューを更新します
今回はvueの操作データが変更されたときのビューの更新についてお届けします。 vueの操作データが変更されてビューが更新されたときの注意事項は次のとおりです。
はじめに
3 か月前、レスポンシブ データを実現する方法を分析するために vue のソース コードを読みました。最後に、Watcher の update() を分析しました。データが変更された後にこのメソッドが呼び出されます。それでは、3 か月後に update() が何をするのかを見てみましょう (私は過去 3 か月で React-native を使用したプロジェクトを実行しましたが、それを要約するつもりはありません。単純すぎるようです)。
この記事の説明スタイル Tree vine について詳しく知るために、私がチェックした vue のバージョンは 2.5.2 でした。コメントを記録するためのソース コード。
目的
調査の方向性を明確にすることによってのみ、目標を達成できます。まず、データの変更後にビューを更新するためにどのようなメソッドが実行されるかについて説明します。この方向で vue のソース コードの入り口から答えを探し始めます
前の結論から始めましょう
前の結論を復習しましょう 結論:
vue が構築されると、Observer オブジェクトがデータ上に作成されます (そして他のフィールド)、getter と setter がインターセプトされ、getter が依存関係の収集をトリガーし、setter が通知をトリガーします。
もう 1 つのオブジェクトは Watcher であり、watch を登録します。watch オブジェクトは 1 回呼び出され、これにより watch オブジェクトの getter がトリガーされ、収集が行われます。現在の Watcher の deps に依存関係を追加します。 dep セッターがトリガーされると、現在の Watcher は Watcher の update() メソッドを呼び出すように通知されます。
そこで、まずレンダリング関連の Watcher を登録します。 src/core/instance/lifecycle.js のファイル
new Watcher(vm, updateComponent, noop, null, true /* isRenderWatcher */)
レンダリング関連の Watcher が mountComponent() メソッドで呼び出されているので、このメソッドが呼び出される場所は 2 か所だけです。 src/platforms/web/runtime/index.js と src/platforms/weex/runtime/index.js、Web を例に挙げます:
Vue.prototype.$mount = function ( el?: string | Element, hydrating?: boolean ): Component { el = el && inBrowser ? query(el) : undefined return mountComponent(this, el, hydrating) }
以上です。mountComponent() を呼び出す $mount() メソッドです。 (または、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 フック
- Watcher を作成します
- マウントされたフックを呼び出します
- (笑) 次に、中心となるのは Watcher を作成することです
見てください Watcher のパラメータ: vm はこれ、updateComponent は a function、noop は空、null は空、true は RenderWatcher を意味します。
Watcher で isRenderWatcher を調べました:
if (isRenderWatcher) { vm._watcher = this }
はい、Watcher で使用するコピーを作成しただけです。初めてパッチを適用したときに、何かを判断しました (からコメント、それが何のためのものなのかはまだわかりません)。
次に、未解決の問題が 1 つだけあります。それは、Watcher の
updateComponentの 2 番目のパラメーターです。関数を使用すると、この関数がウォッチャーのゲッターになります。賢明な方であれば、ウォッチャーがビュー内で依存関係を確立する前に、ビュー内のすべてのデータのゲッターをこの updateComponent で呼び出す必要があることを推測しているはずです。データの変更に応答できます。
updateComponent = () => { vm._update(vm._render(), hydrating) }
次に、vm._update() と vm._render() に移動します。 src/core/instance/render.js に ._render() メソッドが見つかりました
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 } }
このメソッドは、 :
現在の VM の render メソッドに基づいて VNode を生成します (render メソッドはテンプレートまたは vue ファイルからコンパイルされる可能性があるため、render メソッドを直接記述するのが最も効率的であると推測されます)
render メソッドに問題がある場合は、まず renderError メソッドを呼び出し、失敗した場合は最後の vnode または null を読み取ります。親ノードがある場合は、それを独自の .parent 属性に入れます。
-
最後に VNode に戻ります
-
それで、核心はこの文です:
vnode = render.call(vm._renderProxy, vm.$createElement)
ログイン後にコピー render()、vm._renderProxy、vm.$createElement が何なのかわかりません。 -
先看vm._renderProxy: 是initMixin()的时候设置的, 在生产环境返回vm, 开发环境返回代理, 那么我们认为他是一个可以debug的vm(就是vm), 细节之后再看.
vm.$createElement的代码在vdom文件夹下, 看了下是一个方法, 返回值一个VNode.
render有点复杂, 能不能以后研究, 总之就是把template或者vue单文件和mount目标parse成render函数.
小总结: vm._render()的返回值是VNode, 根据当前vm的render函数
接下来看vm._update()
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) { const vm: Component = this if (vm._isMounted) { callHook(vm, 'beforeUpdate') } // 记录update之前的状态 const prevEl = vm.$el const prevVnode = vm._vnode const prevActiveInstance = activeInstance activeInstance = vm vm._vnode = vnode // Vue.prototype.patch is injected in entry points // based on the rendering backend used. if (!prevVnode) { // 初次加载, 只有_update方法更新vm._vnode, 初始化是null // initial render vm.$el = vm.patch( // patch创建新dom vm.$el, vnode, hydrating, false /* removeOnly */, vm.$options._parentElm, vm.$options._refElm ) // no need for the ref nodes after initial patch // this prevents keeping a detached DOM tree in memory (#5851) vm.$options._parentElm = vm.$options._refElm = null } else { // updates vm.$el = vm.patch(prevVnode, vnode) // patch更新dom } activeInstance = prevActiveInstance // update vue reference if (prevEl) { prevEl.vue = null } if (vm.$el) { vm.$el.vue = vm } // if parent is an HOC, update its $el as well if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) { vm.$parent.$el = vm.$el } // updated hook is called by the scheduler to ensure that children are // updated in a parent's updated hook. }
ログイン後にコピー我们关心的部分其实就是patch()的部分, patch()做了对dom的操作, 在_update()里判断了是否是初次调用, 如果是的话创建新dom, 不是的话传入新旧node进行比较再操作.
结论
vue的视图渲染是一种特殊的Watcher, watch的内容是一个函数, 函数运行的过程调用了render函数, render又是由template或者el的dom编译成的(template中含有一些被observe的数据). 所以template中被observe的数据有变化触发Watcher的update()方法就会重新渲染视图.
遗留
render函数是在哪里被编译的
vue源码发布时引入不同平台最后打成dist的流程是什么
patch和VNode的分析相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
以上がVue はデータ変更を操作し、ビューを更新しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









Blizzard Battle.net のアップデートが 45% で止まってしまいます。解決するにはどうすればよいですか?最近、ソフトウェア更新時にプログレスバーが 45% で止まってしまうことが多く、何度再起動しても進まないことがありますが、この状況を解決するにはどうすればよいでしょうか? クライアントの再インストール、リージョンの切り替え、ファイルの削除などが考えられます。このソフトウェアチュートリアルでは、より多くの人に役立つことを願って、操作手順を共有します。 Blizzard Battle.net のアップデートが 45% で止まってしまいます、どうすれば解決しますか? 1. クライアント 1. まず、クライアントが公式 Web サイトからダウンロードされた正式バージョンであることを確認する必要があります。 2. そうでない場合、ユーザーはアジアのサーバー Web サイトにアクセスしてダウンロードできます。 3. 入力後、右上隅の「ダウンロード」をクリックします。注: インストール時に簡体字中国語を選択しないようにしてください。

エピックセブンは、2月22日正午にノンストップでアップデートされることが確認されました。このアップデートでは、レイアの限定召喚率の増加やスイートミラクル、謎のアップデートなど、多くの新しいアクティビティやコンテンツが追加されます。カードプール、スペシャルサイドストーリー「ミラクルメイドキングダム」の2週目が始まりましたので、今回のアップデートを紹介していきます。モバイルゲーム更新スケジュール: セブンスエピックは2月22日更新: ミラクルメイドキングダム第2週オープン ※「レイア」「スイートミラクル」の限定召喚確率がアップ! ■限定召喚チャンスアップ時間: ~2024/02/22(木) 11:00 ~ 2024/03/07(木) 10:59 ■キャラクター属性と職業: 自然属性、戦士 ■キャラクター紹介: 4人組バンド・ザ「ミラクルメイドキングダム」のサブボーカル、ベイさん

1 分で完了: pip バージョンを更新する方法、具体的なコード例が必要です Python の急速な発展に伴い、pip は Python パッケージ管理の標準ツールになりました。ただし、時間の経過とともに、pip バージョンは常に更新されるため、最新の機能を使用し、潜在的なセキュリティ脆弱性を修正できるようにするには、pip バージョンを更新することが非常に重要です。この記事では、pip を 1 分で素早く更新する方法と具体的なコード例を説明します。まず、コマンド ライン ウィンドウを開く必要があります。 Windows システムでは、次のように使用できます。

Angular.js は、動的アプリケーションを作成するための無料でアクセスできる JavaScript プラットフォームです。 HTML の構文をテンプレート言語として拡張することで、アプリケーションのさまざまな側面を迅速かつ明確に表現できます。 Angular.js は、コードの作成、更新、テストに役立つさまざまなツールを提供します。さらに、ルーティングやフォーム管理などの多くの機能も提供します。このガイドでは、Ubuntu24 に Angular をインストールする方法について説明します。まず、Node.js をインストールする必要があります。 Node.js は、ChromeV8 エンジンに基づく JavaScript 実行環境で、サーバー側で JavaScript コードを実行できます。ウブにいるために

「Lantern and Dungeons」は2月29日にアップデートされることが決定しており、アップデート後は「Lantern and Dungeons」のリマスター版が発売され、「ネザの伝説」との連動も予定されている。職業を変更したり、プレイヤーが直接ジョブチェンジしたり、ダンジョンコンテンツも拡張されたり、新たなダンジョンエリアがオープンしたりする予定です。モバイルゲーム更新スケジュール ランタンとダンジョンは2月29日更新:リマスター版╳「ネザの伝説」連動版キーコンテンツ 新しい職業、なぜ転職に誘われるの? 点灯夫って実は転職できるの? こんなカッコいい装備は本当に人を欲張りにする転職後はランタン持ちもカッコいいスキルをたくさん覚えられるそうですよ ゴローさんは「タイパンツは熱い!」と叫んだ。ネザの伝説が集結!天地の輪を手にホットホイールを踏みます♫~知恵と勇気を兼ね備えた小さな英雄、ネザと小さなドラゴンガールがやって来ます

Meituan Takeout Merchant Edition の運用プロセスにおいて、配達開始価格の設定は重要なリンクです。合理的な開始配達価格は、販売者がコストを管理するのに役立つだけでなく、注文量をある程度増やすことができるため、全体的な収益も増加します。ただし、多くの販売者は最低配達価格を変更する方法についてあまり知りません。そこで、次の記事では、この Web サイトの編集者が販売者向けに詳細な開始価格設定ガイドをお届けします。さらに詳しく知りたい場合は、次の記事を参照してください。 Meituan Takeout Merchant Center にログインして店舗設定を入力し、店舗管理を選択し、店舗管理ページ上部のナビゲーション切り替えで配送情報を選択し、配達エリアを追加をクリックして操作を完了します。場所を追加すると、対応する送料が自動的に表示されます。ご注文完了後、お手元に届きます

友人のコンピュータにはこのような障害があり、「この PC」と C ドライブのファイルを開くと、「Explorer.EXE Windows は指定されたデバイス、パス、またはファイルにアクセスできません。プロジェクトにアクセスするための適切な権限がない可能性があります。」と表示されます。フォルダ、ファイル、このコンピュータ、ごみ箱などを含め、ダブルクリックするとこのようなウィンドウが表示されますが、通常は右クリックで開きます。システムのアップデートが原因でこの状況が発生した場合は、以下のエディターで解決方法を説明します。 1. レジストリ エディターを開いて Win+R と入力し、「regedit」と入力するか、スタート メニューを右クリックして実行し、「regedit」と入力します。 2. レジストリ「Computer\HKEY_CLASSES_ROOT\PackagedCom\ClassInd」を見つけます。

MSI グラフィックス カードは、市場で主流のグラフィックス カード ブランドです。パフォーマンスを実現し、互換性を確保するには、グラフィックス カードにドライバーをインストールする必要があることがわかっています。では、MSI グラフィックス カード ドライバーを最新バージョンに更新するにはどうすればよいでしょうか?通常、MSI グラフィック カード ドライバーは公式 Web サイトからダウンロードしてインストールできます。グラフィックカードドライバーの更新方法: 1. まず、「MSI公式Webサイト」に入ります。 2. 入力後、右上隅の「検索」ボタンをクリックし、グラフィックス カードのモデルを入力します。 3. 次に、対応するグラフィックス カードを見つけて、詳細ページをクリックします。 4. 次に、上の「テクニカル サポート」オプションを入力します。 5.最後に「ドライバーとダウンロード」に進みます。
