今日は、早速本題に入り、面接中に尋ねられた質問、つまりキープアライブ コンポーネントのキャッシュ原理についてお話ししましょう。 公式APIの紹介と使用方法
公式サイトの例では、タブ切り替えによってユーザーの操作が保存されています。実際には、一覧ページから詳細ページにジャンプし、一覧ページに戻るという状況にも遭遇する可能性があります。ユーザーのフィルタリング操作を保存する必要があり、そのためには <keep-alive> を使用する必要があります。これにより、再レンダリングを回避し、ページのパフォーマンスを向上させることもできます。 使用方法と小道具の説明// 動的コンポーネントでのキープアライブコンポーネントの使用。その他の使用方法については、公式ウェブサイト <keep-alive include="['コンポーネント名A', 'コンポーネント名B']" 除外="'コンポーネント名C'" :max="10"> <コンポーネント :is="view"></コンポーネント> </キープアライブ>
知らせ:
ソースコードの解釈まずソースコードの画像を投稿する 全部で125列ありますが、片付けてみるとそんなにたくさんのものは入っていません。最初に、必要なメソッドをいくつか紹介し、次にキープアライブコンポーネント自体が使用するメソッドをいくつか定義します。最後に、keep-alive というコンポーネントオプションが外部に公開されます。abstract を除いて、これらすべてのオプションはよく知られています。その中でも、レンダリング関数はキャッシュ原則の最も重要な部分です。また、キープアライブコンポーネントは機能コンポーネントであることがわかります。 // isRegExp 関数は正規表現かどうかを判定し、remove は配列内のメンバーを削除します。// getFirstComponentChild は VNode 配列の最初の有効なコンポーネントを取得します。import { isRegExp, remove } from 'shared/util' 'core/vdom/helpers/index' から { getFirstComponentChild } をインポートします。 type VNodeCache = { [key: string]: ?VNode }; // キャッシュコンポーネントのキャッシュタイプ VNode // コンポーネント名またはコンポーネントタグでコンポーネント名を取得します (上記の 2 番目のポイント) 関数 getComponentName (opts: ?VNodeComponentOptions): ?string { opts && (opts.Ctor.options.name || opts.tag) を返します } // include または exclude がコンポーネント名に一致するかどうかを判定します。関数 matches (pattern: string | RegExp | Array<string>, name: string): boolean { if (Array.isArray(パターン)) { return pattern.indexOf(name) > -1 // include または exclude は配列です} else if (typeof pattern === 'string') { return pattern.split(',').indexOf(name) > -1 // include または exclude は文字列です } else if (isRegExp(pattern)) { return pattern.test(name) // include または exclude は正規表現です} false を返します // いずれも一致しません (上記の 2 番目と 3 番目の点に注意してください) } // キャッシュを破棄する function pruneCache (keepAliveInstance: any, filter: Function) { const { cache, keys, _vnode } = keepAliveInstance // キープアライブコンポーネントインスタンス for (const key in cache) { const cachedNode: ?VNode = cache[key] // キャッシュされたコンポーネント if (cachedNode) { 定数名: ?string = getComponentName(cachedNode.componentOptions) // 名前が存在し、include または exclude に一致しない場合は、キャッシュされたコンポーネントを破棄します if (name && !filter(name)) { pruneCacheEntry(キャッシュ、キー、キー、_vnode) } } } } //キャッシュエントリを破棄する関数pruneCacheEntry( キャッシュ: VNodeCache、 キー: 文字列、 キー: 配列<文字列>, 現在の?: VNode ){ const cached = cache[key] // キャッシュされたコンポーネント // 変更があった場合に「コンポーネントのキャッシュを継続するかどうか」 // コンポーネントがキャッシュされていて、現在のコンポーネントが存在しないか、キャッシュされたコンポーネントのタグが現在のコンポーネントのタグと等しくない場合 if (cached && (!current || cached.tag !== current.tag)) { // これは、コンポーネントをキャッシュする必要がなくなったことを意味します。コンポーネントインスタンスを破棄します。cached.componentInstance.$destroy() } cache[key] = null // キャッシュ内のこのコンポーネントをnullに設定する remove(keys, key) // このコンポーネントのキーをキー配列から削除します} // 例 type const patternTypes: Array<Function> = [String, RegExp, Array] // キープアライブコンポーネントのいくつかのオプションを公開する export default { name: 'keep-alive', // コンポーネント名 abstract: true, // keep-alive は抽象コンポーネントです // キープアライブコンポーネントを使用するときに渡される3つのプロパティ 小道具: { 含まれるもの: パターンタイプ、 除外: パターンタイプ、 最大: [文字列、数値] }, 作成された(){ this.cache = Object.create(null) // キャッシュする必要があるコンポーネントを保存します this.keys = [] // キャッシュする必要がある各コンポーネントのキー、つまり this.cache オブジェクトに対応するキー値を保存します}, // キープアライブコンポーネントを破棄するときは、キャッシュ内の各コンポーネントを破棄します。destroyed() { for (const キー in this.cache) { キャッシュエントリを削除します(this.cache、キー、this.keys) } }, // キープアライブコンポーネントがマウントされると、include と exclude の変更を監視し、条件が満たされるとキャッシュされたコンポーネントを破棄します。mounted() { this.$watch('include', val => { pruneCache(this、name => matches(val、name)) }) this.$watch('exclude', val => { pruneCache(this、name => !matches(val、name)) }) }, // ポイントはここです render () { const slot = this.$slots.default // キープアライブコンポーネントのデフォルトスロット const vnode: VNode = getFirstComponentChild(slot) // デフォルトスロットの最初の有効なコンポーネントを取得します // vnode が存在する場合は、vnode のオプションを取得します const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions if (コンポーネントオプション) { //最初の有効なコンポーネントの名前を取得します 定数名: ?string = getComponentName(componentOptions) const { include, exclude } = this // props によって渡される include と exclude もし ( // include が存在し、name が存在しないか、name が一致しない場合 (include && (!name || !matches(include, name))) || // exclude が存在し、name が存在するか、name が一致する場合 (exclude && name && matches(exclude, name)) ){ return vnode // キャッシュは不要であり、このコンポーネントはレンダリングのために直接返されることを示します} // 一致した場合はキャッシュ操作が必要です const { cache, keys } = this // キープアライブコンポーネントのキャッシュコンポーネントと、キャッシュコンポーネントに対応するキー // 最初の有効なコンポーネントのキーを取得します 定数キー: ?string = vnode.key == null // 同じコンストラクターを異なるローカル コンポーネントとして登録できます // cid だけでは不十分なので、連結してみましょう。componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '') : vnode.キー // このコンポーネントがキャッシュにヒットした場合 if (cache[key]) { // このコンポーネントインスタンスはキャッシュ内のコンポーネントインスタンスに置き換えられます vnode.componentInstance = cache[key].componentInstance // keysremove(keys, key) 内の現在のキーの位置を更新します // keys から現在のキーを削除しますkeys.push(key) // それを keys の末尾に配置します} else { // キャッシュにヒットしない場合は、このコンポーネントをキャッシュに追加します。cache[key] = vnode keys.push(key) // このコンポーネントのキーをキーの末尾に配置します // キャッシュ内のコンポーネントの数が渡された最大値を超える場合、キャッシュ内の LRU コンポーネントを破棄します if (this.max && keys.length > parseInt(this.max)) { キャッシュエントリを削除します(キャッシュ、キー[0]、キー、this._vnode) } } vnode.data.keepAlive = true // このコンポーネントのkeepAliveプロパティをtrueに設定します } // 最初の有効なコンポーネントが存在するが、そのcomponentOptionsが存在しない場合は、レンダリングのためにこのコンポーネントを返します。 // または、有効な最初のコンポーネントが存在しないが、keep-aliveコンポーネントのデフォルトスロットが存在する場合は、レンダリングのためにデフォルトスロットの最初のコンポーネントを返します。 return vnode || (slot && slot[0]) } } 補充:最初の古いキャッシュ コンポーネントを削除し、キャッシュ コンポーネント キーを更新する上記の順序では、実際には LRU キャッシュ削除戦略が使用されます。 要約する簡単に要約すると次のようになります。 キープアライブコンポーネントがレンダリングされるとき、渡された include と exclude に従って、キープアライブでラップされた名前付きコンポーネントと一致します。一致しない場合は、レンダリングのために名前付きコンポーネントを直接返します。一致した場合は、キャッシュ操作を実行します。コンポーネントがすでにキャッシュに存在する場合は、そのインスタンスが置き換えられ、keys 内のコンポーネントのキーの位置が更新されます。コンポーネントがキャッシュに存在しない場合は、コンポーネントがキープアライブコンポーネントのキャッシュに配置され、keys にコンポーネントのキーが配置されます。include と exclude はマウント時に監視されるため、後でこの 2 つの属性の値が変化すると、条件が満たされているかどうかが再度判断され、コンポーネントが破棄されます。 これで、ソース コードの観点からキープアライブ コンポーネントのキャッシュの原理に答えるこの記事は終了です。キープアライブ コンポーネントのキャッシュに関するより関連性の高いコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
<<: MySQL 5.7.17 winx64 のインストールと設定のグラフィックチュートリアル
>>: Windows が MySQL サービスを開始できず、エラー 1067 を報告する場合の解決策
目次分割代入を使用したオブジェクトパラメータコールバック関数の命名条件文を説明的にするスイッチ文をM...
この記事では、虫眼鏡効果を実現するためのJavaScriptの具体的なコードを参考までに紹介します。...
目次序文ステップ序文今日、es ログが記録されていないことに気付きました。filebeat、elas...
CSS画像結合技術1. 画像のステッチ画像ステッチング技術は、個々の画像を収集する技術です。画像の多...
ブラウザが IE のどのバージョンであるかを検出するためによく使用される JavaScript コー...
1. データ重複排除日常業務では、Hive や Impala を使用してクエリとエクスポートを行う際...
01. コマンドの概要dirname - ファイル名からディレクトリ以外のサフィックスを削除しますd...
この記事では、例を使用して MySQL 正規表現 (regexp および rlike) の検索機能を...
質問最近、SSH フレームワークを使用して実用的なプロジェクトを完了していたときに、長い間悩まされて...
テキスト入力でプレースホルダーを使用していますが、問題なく動作します。しかし、選択ボックスにはプレー...
nginx 設定ファイルは主に 4 つの部分に分かれています。 main{#(グローバル設定) ht...
HTML5 では、入力用のネイティブ プレースホルダー属性が追加されており、これは高度なブラウザでサ...
Linux でダイナミック ライブラリをロードできません次のような異常事態が発生した場合./test...
序文最近、X 省のコールド チェーン トレーサビリティ システムの開発で忙しくしています。毎日午後 ...
MySQL インストール パッケージをダウンロードします。mysql-8.0.11-winx64 を...