1. ライフサイクルとは何ですか?また、これらのライフサイクルでどのようなことが行われましたか?
beforeCreate 作成前に; 応答データを取得できません
作成後、ここに読み込みイベントを追加し、データ要求を行うことができます。
Mount がマウントされる前に、ロードはここで終了し、関数の自己実行を実装するためにいくつかの初期データが取得されます。
マウント後、ここでバックエンド リクエストを開始し、データを取得し、ルーティング フックで何らかの処理を行います。
beforeUpdate データ更新前
更新データが更新された後、
beforeDestroy、XX を削除してもよろしいですか? それとも終了を確認しますか?
破棄されました 破棄後、現在のコンポーネントは削除され、関連するコンテンツはクリアされました。ここでは DOM を取得できません。
2. コンポーネント通信
父传子:props、$attrs/$listeners、$children、$root、provide/inject、$refs
息子から父親へ: $emit、$parent、
兄弟:eventBus、vuex
3. ページ通信
URL スプライシング パラメータ: "/a?a1=a1"、受信ページ: this.$route.query.a1
クエリパラメータ: {パス: 'a'、クエリ: {a2:'a2'}}、受信ページ: this.$route.query.a2
params: {name: 'a'、params: {a3:'a3'}}、受信ページ: this.$route.params.a3
動的ルーティングパラメータ: /path/a4、受信ページ: this.$route.params.id、ルーティング: パス: "/a/:id"
4. $set は何をしますか?
オブジェクトの新しく追加された属性や配列の新しく追加されたメンバーなど、データは変更されるがビューが更新されない場合に使用されます。
this.$set(obj,"キー","値")
5. $nextTick は何をしますか?
次の DOM 更新サイクルの後に遅延コールバックを実行します。データを変更した直後にこのメソッドを使用して、更新された DOM を取得します。
たとえば、作成したライフサイクル中に dom を操作したい場合に使用できます。
this.$nextTick(()=>{ ... }) はマウント前のライフサイクルで dom を操作できます
6. mixin は何をしますか?
Vue コンポーネントで再利用可能な関数を配布する非常に柔軟な方法を提供します。ミックスインには、任意のコンポーネント オプションを含めることができます。コンポーネントがミックスインを使用する場合、ミックスインのオプションはすべてコンポーネント自体のオプションに「混合」されます。
var mixin = { データ: 関数 () { 戻る { メッセージ: 「こんにちは」、 foo: 'abc' } } } 新しいビュー({ ミックスイン: [ミックスイン]、 データ: 関数 () { 戻る { メッセージ: 「さようなら」、 バー: 'デフォルト' } }、 作成されました: 関数 () { console.log(this.$data) // => { メッセージ: "さようなら"、foo: "abc"、バー: "def" } } })
7. MVVM の理解について簡単に説明します。
MVVMはModel-View-ViewModelの略称です。Model はデータモデルを表し、データの変更や操作のためのビジネス ロジックも Model 内で定義できます。ビューは、データ モデルを表示用の UI に変換する役割を担う UI コンポーネントを表します。ViewModel は、モデル データの変更を監視し、ビューの動作を制御し、ユーザー インタラクションを処理します。簡単に理解すると、View と Model を同期し、Model と View を接続するオブジェクトです。MVVM アーキテクチャでは、ビューとモデルの間に直接の接続はありません。代わりに、ビューモデルを介して対話します。モデルとビューモデルの間の対話は双方向であるため、ビュー データの変更はモデルに同期され、モデル データの変更は同期されます。 Viewにもすぐに反映されます。ViewModel は、双方向のデータ バインディングを通じて View 層と Model 層を接続し、View と Model 間の同期は人間の介入なしで完全に自動化されるため、開発者はビジネス ロジックに集中するだけでよく、DOM を手動で操作する必要はありません。データ状態の同期には注意が必要ですが、複雑なデータ状態の維持はMVVMによって完全に管理されます。
8. 監視と計算の違い
Watch はデータ内のデータ変更のみを監視できます。Computed は監視する必要はありません。Watch は非同期操作を実行できます。Computed は実行できません。Computed は元のデータを変更しません。処理されたデータは return を通じて返され、多数の論理操作を含むことができます。
9. v-if と v-show の違い
9.1. v-show は単に要素の表示属性を制御するだけですが、v-if は条件付きレンダリングです (条件が true の場合、要素はレンダリングされ、条件が false の場合、要素は破棄されます)。
9.2. v-show の最初のレンダリングのオーバーヘッドは高くなりますが、v-if の最初のレンダリングのオーバーヘッドははるかに小さいです。
9.3. v-if はスイッチング オーバーヘッドが高くなりますが、v-show はスイッチング オーバーヘッドが小さいです。
9.4. v-if には一致する v-else-if と v-else がありますが、v-show はありません。
9.5. v-if はテンプレートで使用できますが、v-show は使用できません。
10. v-for と v-if を一緒に使用できないのはなぜですか?
v-for は v-if よりも高い優先順位を持ちます
要素に対して v-if と v-for を同時に使用しないでください。パフォーマンスが無駄になります (各レンダリングは最初にループし、次に条件判断を実行します)。
この状況を回避するには、テンプレートを外層にネストし(ページレンダリングでは dom ノードは生成されません)、この層で v-if 判定を実行し、内部で v-for ループを実行します。
<template v-if="isShow"> <p v-for="アイテム内のアイテム"> </テンプレート>
条件がループ内に表示される場合は、計算された属性を通じて事前に表示する必要のない項目を除外できます。
計算:{ アイテム:関数(){ return this.list.filter(function(item){ 返品商品.isShow }) } }
11. キーの機能は何ですか? 値としてインデックスと ID を記述するのはどちらが良いですか?
キーは、各 vnode の一意の ID を指定します。同じレベルの vnode の差分プロセス中に、キーに基づいて簡単に比較して、それらが同じノードであるかどうかを判断できます。キーの一意性を使用して、取得するマップ オブジェクトを生成します。対応するノードをトラバースするよりも高速です メソッドの方が高速です キーを指定した後、レンダリングの精度を保証できます (DOM 要素を可能な限り再利用します) 値を割り当てるときは、ID を最初に使用する必要があります。
12. フィルターの使い方
// グローバルでの使用 Vue.filter('globalFilter', function(){ // ... }) // ローカルでの使用 フィルタ: { formatMoney(数値) { // ... }、 } <p>フィルター{ { お金 | フォーマットマネー }}</p>
13. vuex の 5 つのコアは何をしますか?
state: Vuexの基本データ、補助関数mapState
Getters: ストアの状態から派生した状態。計算されたプロパティ、補助関数の MapGetter に似ています。
ミューテーション: Vuex のストアの状態を変更する唯一の方法、同期的、補助関数のマップミューテーション
アクション: アクションは、状態を直接変更するのではなく、突然変異を送信します。アクションには、任意の非同期操作を含めることができます。ヘルパー関数のマップアクション
モジュール: Vuex を使用すると、ストアをモジュールに分割できます。各モジュールには独自の状態、突然変異、アクション、ゲッター、さらにはネストされたサブモジュールがあり、上から下へ同様の分割が行われます。
14. ミューテーションとアクションメソッドの呼び出し方法
ミューテーションの呼び出し: $store.commit('ミューテーションで定義されたメソッド') アクションの呼び出し: $store.dispatch('アクションで定義されたメソッド') アクションはミューテーションでメソッドを呼び出します。 fn(コンテキスト){ context.commit('ミューテーションで定義されたメソッド'); }
15. vue-router の一般的に記述される属性は何ですか?
ルーターリンクの共通属性:
toは対象ルートのリンクを表します
replace に replace 属性が設定されている場合、クリックすると、router.push() の代わりに rober.replace() が呼び出されるため、ナビゲーション後に履歴レコードは残されません。つまり、前のページに戻ることはできません。
append で append 属性を設定した後、ベース パスが現在のパスの前に追加されます。たとえば、/a から相対パス b に移動します。append が構成されていない場合、パスは /b です。構成されている場合は、 /a/b。
タグ <router-link> を <li> などの特定のタグにレンダリングしたい場合があります。そこで、tag prop クラスを使用してタグの種類を指定します。それでもクリックをリッスンしてナビゲーションをトリガーします。
active-class は、リンクがアクティブ化されたときに使用される CSS クラス名を設定します。デフォルト値は、ルートの構築オプション linkActiveClass を通じてグローバルに設定できます。デフォルト値は「router-link-active」です。
正確に「アクティブ化するかどうか」を指定します。デフォルトは false です。
vue-router の共通プロパティ:
パスルーティングパス
名前 路線名
コンポーネントインポートルーティングコンポーネント
リダイレクトルートリダイレクト
モードルーティングモード
子のサブルート
メタルーティングメタ情報
16. ルーティング ガードとは何ですか?また、その機能は何ですか? 3 つのパラメータは何に使用されますか?
グローバル ガード: beforeEach (ログイン インターセプト)、afterEach
ルート排他ガード: beforeEnter (一部のルートのログイン傍受)
コンポーネント内のガード: beforeRouteEnter (権限管理)、beforeRouteUpdate、beforeRouteLeave
ルーティンググローバル解決ガード: beforeResolve (ここで、単一ページ名の方向によって、アクセスされるインターフェースのドメイン名も異なります)
3 つのパラメータ: to: どこに行くか、from: どこから来るか、next: 次のステップ
ページ a からページ b に入るときにトリガーされるライフサイクル 1.beforeRouteLeave: ルーティング コンポーネントのコンポーネントはルーティング前にフックを離れるため、ルーティングの離脱をキャンセルできます。 2.beforeEach: グローバル ルーティング ガード。ログイン検証、グローバル ルーティングの読み込みなどに使用できます。 3.beforeEnter: ルート排他ガード 4.beforeRouteEnter: ルーティングされたコンポーネントがルートに入る前のフック。 5.beforeResolve: ルーティングのグローバル解像度ガード 6.afterEach: ルーティング グローバル ポスト フック 7.beforeCreate: コンポーネントのライフサイクル。これにはアクセスできません。 8.created: コンポーネントのライフサイクル。これにはアクセスできますが、dom にはアクセスできません。 9.beforeMount: コンポーネントのライフサイクル 10.非アクティブ化: キャッシュコンポーネント a をそのままにするか、 a の beforeDestroy および破棄されたコンポーネント破棄フックをトリガーします。 11.mounted: dom にアクセス/操作します。 12.アクティブ化: キャッシュ コンポーネントを入力し、(存在する場合) のネストされたサブコンポーネントを入力します。 13. 次に beforeRouteEnter コールバック関数を実行します。
17. ハッシュモードとヒストリーモードの違い
ハッシュ モードでは、URL の後に # アンカー ポイントを書きます。ハッシュ値の変更によってブラウザがサーバーにリクエストを送信することはなく、ハッシュの変更によって hashchange イベントがトリガーされるためです (hashchange は、URL フラグメントの後にのみ変更できます) #); さらに重要な点は、ハッシュの変更がブラウザによって記録される URL であるため、ブラウザの前方および後方を使用できることがわかるため、HTML5 の歴史が登場する前は、人々は基本的にハッシュを使用してフロントを実装していました。 - ルーティング終了。
ヒストリーモード: ハッシュはIE8と互換性あり、ヒストリーはIE10とのみ互換性あり; ハッシュは本来ページの位置決めに使用されますが、ルーティングに使用される場合、本来のアンカー機能は使用できません。次に、ハッシュ パラメータは URL に基づいています。複雑なデータを転送したい場合は、容量制限が発生します。ただし、ヒストリ モードでは、パラメータを URL に入れるだけでなく、特定のオブジェクトにデータを保存することもできます。履歴 API は、切り替え (戻る、進む、進む) と変更 (pushState ,
replaceState) の 2 つの部分に分けることができます。履歴モードの問題点: 更新するのが怖い。
18. 一般的に使用される命令とそのカスタマイズ方法について話しましょう。
v-if: true の場合はノードをレンダリングし、それ以外の場合はノードをレンダリングしません。
v-if、v-else、v-else-if: js 風の if...else 判定ステートメント
v-show: display:none を通じて要素の表示と非表示を制御します。
v-for: ループ。v-for は v-if よりも優先され、併用することはお勧めできません。
v-bind: バインド属性、
v-on: バインディング イベント、
.stop はイベントが伝播し続けるのを防ぎます
.prevent イベントによってページがリロードされなくなりました
.capture はイベント キャプチャ モードを使用します。つまり、要素自体によってトリガーされたイベントが最初にここで処理され、次に内部要素に渡されて処理されます。
.self は、event.target が現在の要素自体である場合にのみハンドラー関数をトリガーします。
.once イベントは 1 回だけトリガーされます
.passive は、イベントのデフォルトの動作をブロックしたくないことをブラウザーに伝えます。
v-model: 双方向データ バインディング
.lazy デフォルトでは、v-model は入力ボックスの値とデータを同期します。この修飾子を使用して、変更イベントで再同期に切り替えることができます。
.number は、ユーザーの入力値を数値型に自動的に変換します。
.trim は、ユーザーが入力した先頭と末尾のスペースを自動的にフィルタリングします。
v-text および v-html: textContent を更新し、実際の HTML 構造を出力するために使用されます。
v-pre: 主に、この要素とそのサブ要素のコンパイル プロセスをスキップするために使用されます。
v-cloak: コンパイルする関連インスタンスが終了するまで要素上に留まります。
v-once: 関連付けられたインスタンスは 1 回だけレンダリングされます。後続の再レンダリングでは、インスタンスとそのすべての子は静的コンテンツとして扱われ、スキップされるため、更新パフォーマンスを最適化するために使用できます。
// カスタム命令 v-focus ディレクティブ: { 集中: { // 命令の定義 挿入: function(el) { el.focus(); }、 }、 }、
19. vueスロットの使い方
// たとえば、新しい <base-layout> コンポーネントを作成します。 <div class="コンテナ"> <ヘッダー> <スロット名="ヘッダー"></スロット> </ヘッダ> <メイン> <スロット></スロット> </メイン> <フッター> <slot name="フッター"></slot> </フッター> </div> // スロットを使用する <ベースレイアウト> <template v-slot:header> // または <template #header> <h1>ここにページのタイトルが入る可能性があります</h1> </テンプレート> <テンプレート v-スロット:デフォルト> <p>メインコンテンツの段落。</p> <p>そしてもう 1 つ。</p> </テンプレート> <テンプレート v-スロット:フッター> <p>連絡先情報は次のとおりです</p> </テンプレート> </ベースレイアウト> // スコープ スロット(新しい <current-user> コンポーネントの作成など) <スパン> <slot v-bind:user="ユーザー"> { { ユーザーの姓 }} </スロット> </スパン> // スロットを使用する <現在のユーザー> <template v-slot:default="slotProps"> { {slotProps.user.firstName }} </テンプレート> </現在のユーザー> // または省略形 <current-user v-slot="slotProps"> { {slotProps.user.firstName }} </現在のユーザー>
20. Vue シングルページ アプリケーションの長所と短所
利点: Vue の目標は、可能な限り単純な API を介して応答性の高いデータ バインディングと結合されたビュー コンポーネントを実装することです。中心となるのは応答性の高いデータ バインディング システムです。MVVM、データ駆動型、コンポーネント化、軽量、簡潔、効率的、高速、そしてモジュールに優しい。DOM ではなくデータのみを考慮します。プラグインはたくさんあります。コンディションを維持しやすい。
短所: 下位バージョンのブラウザはサポートしておらず、少なくとも IE9 のみをサポートしています。SEO の最適化には役に立ちません (SEO をサポートしたい場合は、サーバー経由でコンポーネントをレンダリングすることをお勧めします)。初めてホームページをロードすることはできません。自分で前後に移動するには、ブラウザのナビゲーション ボタンを使用する必要があります。
21. SSRを行う理由とその実装方法は何ですか?
検索エンジン クローラーが完全にレンダリングされたページを直接表示できるため、SEO が向上します。
特に遅いネットワーク状態や動作の遅いデバイスの場合、コンテンツの到着時間が短縮されます。多くの場合、ユーザー エクスペリエンスが向上します。
開発条件によって制限されます。ブラウザ固有のコードは、特定のライフサイクル フック関数でのみ使用できます。一部の外部拡張ライブラリは、サーバーでレンダリングされたアプリケーションで実行するために特別な処理が必要な場合があります。
ビルドのセットアップとデプロイメントに関する追加の要件。任意の静的ファイル サーバーにデプロイできる完全に静的なシングル ページ アプリケーション (SPA) とは異なり、サーバーでレンダリングされるアプリケーションは Node.js サーバー実行環境に存在する必要があります。
サーバー側の負荷が増加する
HTML 構造はバックエンドを通じて返され、フロントエンドでレンダリングおよび表示されます。これは Nuxt を使用して実装できます。
22. ルートの遅延読み込みを実装する方法
顧客により良いカスタマー エクスペリエンスを提供するために、最初の画面コンポーネントの読み込みが速くなり、白い画面の問題が解決されます。
必要に応じてページを分割して読み込むことができるため、ホームページの読み込み圧力を効果的に分散できます。
ホームページの読み込みにかかる時間を短縮します。
コンポーネント: () => import('./Foo.vue') // または コンポーネント:resolve => require(['@/components/home'],resolve)
23. Lessでグローバルスタイルを設定する方法
// vue.config.js 中 関数 addStyleResource(rule) { ルール .use("スタイルリソース") .loader("スタイルリソースローダー") .options({ パターン: [path.resolve(__dirname, "./src/assets/less/global.less")]、 }); } // module.export での使用を少なくする css: { ローダーオプション: { 少ない: { 少ないオプション: { javascriptEnabled: true、 globalVars: { プライマリ: "#fff"、 }、 }、 }、 }、 }、 // グローバル変数を減らす chainWebpack: (config) => { const type = ["vue-modules", "vue", "normal-modules", "normal"]; types.forEach((タイプ) => addStyleResource(config.module.rule("less").oneOf(type)) ); }、
24. スコープの機能は何ですか?
スコープ付きは、次のスタイルのスコープが現在のコンポーネントであり、グローバル スタイルに影響を与えないことを意味します。
25. $router と $route の違い
$router はルートジャンプ、$route はルーティング情報です
26. data:{} と data(){return {}} の違い
return でラップされていないデータはプロジェクト内でグローバルに表示され、変数汚染の原因となるため、return でラップした後は、データ内の変数は現在のコンポーネントでのみ有効になり、他のコンポーネントには影響しません。ソースデータを保護する効果があります。
27. Axios の設定、カプセル化、インターセプト、クロスドメイン
// クロスドメイン: config フォルダーのindex.js に devServe を入力します。 proxyTable: { // cli3.0+ は vue.config.js でプロキシを構成します '/api':{ ターゲット: 'プロキシサーバーの宛先アドレス', ChangeOrigin: true、 PathRewrite: {“^/api”:” ”} } }
// カプセル化とインターセプト 「axios」から axios をインポートします。 const http = axios.create({ ベースURL: "/api", タイムアウト: 5000、 ヘッダー: { "コンテキストタイプ": "application/json", }、 }); //リクエストのインターセプト http.interceptors.request.use( (レス) => { // const トークン = sessionStorage.getItem('token') ? sessionStorag.getItem('トークン') : ''; // if(token){ヘッダーにトークンを追加} 応答を返します。 }、 (エラー) => { エラーを返します。 } ); // 応答インターセプト http.interceptors.response.use( (レス) => { // const コード = res.code // if(コード === 404){router.replace()} // if(code === 200){router.replace()} 応答を返します。 }、 (エラー) => { エラーを返します。 } ); 関数 get(url, params = {}) { return new Promise((解決、拒否) => { http .get(url, パラメータ) .then((res) => 解決(res)) .catch((err) => 拒否(err)); }); } 関数 post(url, params = {}) { return new Promise((解決、拒否) => { http .post(url, パラメータ) .then((res) => 解決(res)) .catch((err) => 拒否(err)); }); } エクスポート { 取得、投稿 };
28. cliの各バージョンでプロジェクトをビルドするためのコマンドと起動コマンド
プロジェクトの作成: cli2.0: vue init webpack プロジェクト名 cli3.0+: vue プロジェクト名作成 プロジェクトの開始: cli2.0: npm run dev cli3.0+: npm runserve
29. vue3.0 についてのあなたの理解を簡単に話してください
29.1. vue3.0とvue2.0の最大の違いは、APIがオリジナルのオプションAPIからコンポジションAPI+オプションAPIに変更されたことで、コードの記述がより柔軟になり、再利用率が高くなった点です。
29.2. vue3.0 は vue2.0 より 2 倍高速で、ツリーシェイキングがよりフレンドリーです。
29.3、vue3.0 は TypeScript と PWA をサポートします
29.4. 双方向のデータ バインディングが Object.defineProperty から新しい Proxy に変更され、$set を使用する必要がなくなりました。
29.5. その他の変更: カスタム レンダラーのサポート、フラグメントおよびポータル コンポーネントのサポートなど。
30. 双方向バインディングの原理を簡単に説明します
// パブリッシュ/サブスクライブ モードで実装されたデータ依存関係コレクター クラス Dep { コンストラクター() { this.subs = []; } addSub(サブ) { thissubspush(sub); } 通知() { this.subs.forEach((sub) => sub.update()); } } Dep.depTargets = null; クラスウォッチャー { コンストラクター(データ、ゲッター) { this.getter = ゲッター; this.value = this.get(); } 得る() { Dep.depTargets = this; let value = this.getter(); Dep.depTargets = null; 戻り値; } アップデート() { this.value = this.get(); } } const typeTo = (val) => Object.prototype.toString.call(val); // オブザーバー モードはすべてのプロパティの変更を監視します 関数defineReactive(obj, key, value) { dep = new Dep(); とします。 Object.defineProperty(obj, key, { set(newValue) { if (newValue === 値) が戻る; 値 = 新しい値; dep.notify(); }、 得る() { const topTarget = Dep.depTargets; dep.addSub(topTarget); 戻り値; }、 }); } function walk(obj) {//すべてのプロパティをリッスンする Object.keys(obj).forEach((key) => { if (typeTo(obj[key]) === "[オブジェクト オブジェクト]") { walk(obj[key]); } defineReactive(obj, key, obj[key]); }); } 関数観察(値) { if (typeTo(value) !== "[object Object]") は null を返します。 ウォーク(値); } 観察(this.data); new Watcher(this.data, () => { this.$mounte(this.el); });
31. Vue のパフォーマンスの最適化にはどのようなものが行われていますか?
31.1. ロングリストのパフォーマンスの最適化: Object.freeze メソッドを使用してオブジェクトをフリーズできます。オブジェクトがフリーズされると、変更できなくなります。
デフォルトのエクスポート { データ: () => ({ 本: [] })、 非同期作成() { const books = await axios.get("/api/books"); this.books = Object.freeze(books); } };
31.2. 無限リストのパフォーマンスを最適化する: アプリケーションに非常に長い、または無限にスクロールするリストがある場合、パフォーマンスを最適化するために「ウィンドウ」テクノロジを使用する必要があります。コンテンツの小さな領域のみをレンダリングする必要があるため、再描画の時間が短縮されます。 - コンポーネントのレンダリングと DOM ノードの作成。window.requestAnimationFrameメソッドで遅延読み込み機能を設定できます
setTimeout(() => { //100,000個のデータを挿入 定数合計 = 100000; // 一度に 20 項目、パフォーマンスの問題に応じて調整可能 const MAX_ONCE = 20; //データのレンダリングに必要な回数 const ループカウント = 合計 / MAX_ONCE; countOfRender = 0 にします。 let el = document.querySelector("ul"); 関数 add() { // 最適化します。リフローを引き起こすデータの挿入を許可しません const フラグメント = document.createDocumentFragment(); for (i = 0; i < MAX_ONCE; i++) { const li = document.createElement("li"); li.innerText = `${i} + ${Math.floor(Math.random() * total)}`; フラグメント.appendChild(li); } el.appendChild(フラグメント); countOfRender += 1; ループ(); } 関数ループ() { if (countOfRender < ループ数) { window.requestAnimationFrame(追加); } } ループ(); }, 0);
32. Vueの差分アルゴリズムと仮想dom
仮想 DOM は、ブラウザのパフォーマンスの問題を解決するように設計されています。1 回の操作で DOM に N 回の更新がある場合、仮想 DOM はすぐには DOM を操作せず、N 回の更新の差分コンテンツをローカルの JS オブジェクトに保存し、最後にその JS オブジェクトを DOM ツリーに追加します。大量の不要な計算を避けるために、その後の操作を実行します。したがって、JS オブジェクトを使用して DOM ノードをシミュレートする利点は、すべてのページ更新を最初に JS オブジェクト (仮想 DOM) に反映できることです。メモリ上での JS オブジェクトの操作速度が明らかに速くなります。更新完了後、最終的な JS オブジェクトは実際の DOM にマッピングされ、ブラウザに渡されて描画されます。
Vue の差分アルゴリズム: 同じレベルでのみ比較し、レベル間の操作を無視し、両端から中間まで比較します。
//patch 関数は diff 中に呼び出されます。patch は、それぞれ古いノードと新しいノードを表す 2 つのパラメーター vnode と oldVnode を受け取ります。 関数パッチ (oldVnode、vnode) { if (sameVnode(oldVnode, vnode)) { patchVnode(oldVnode, vnode) } それ以外 { const oEl = oldVnode.el letparentEle = api.parentNode(oEl) createEle(vnode) if (parentEle !== null) { api.insertBefore(parentEle, vnode.el, api.nextSibling(oEl)) api.removeChild(parentEle, oldVnode.el) oldVnode = null } } vnodeを返す } //patch 関数の最初の if は、sameVnode(oldVnode, vnode) を決定して、2 つのノードが同じタイプのノードであるかどうかを判断します。 function SameVnode(oldVnode, vnode){ //2 つのノードのキー値は同じであり、sel 属性値も同じです。つまり、2 つのノードは同じタイプとみなされ、次のステップで比較できます。 return vnode.key === oldVnode.key && vnode.sel === oldVnode.sel } //つまり、div などの同じノード要素が異なる className を持つ場合でも、Vue はそれを 2 つの異なるタイプのノードとみなし、古いノードを削除し、新しいノードを挿入する操作を実行します。これは React diff 実装とは異なり、React は同じノード要素を同じタイプのノードとみなし、そのノードの属性のみを更新します。 //さらに比較するために、同じタイプのノードに対して patchVnode(oldVnode, vnode) を呼び出します。 patchVnode (oldVnode, vnode) { const el = vnode.el = oldVnode.el //vnode.el に現在の実際の dom を参照させます。el が変更されると、vnode.el も同期的に変更されます。 let i、oldCh = oldVnode.children、ch = vnode.children if (oldVnode === vnode) return //古いノード参照と新しいノード参照は一貫しており、変更はありません。 //テキストノードの比較 if (oldVnode.text !== null && vnode.text !== null && oldVnode.text !== vnode.text) { api.setTextContent(el, vnode.text) }それ以外 { updateEle(el, vnode, oldVnode) //子ノードを持つ 2 つのノードの場合 (2 つの子ノードは異なります)、updateChildren を呼び出します。 if (oldCh && ch && oldCh !== ch) { updateChildren(el, oldCh, ch) }else if (ch){ //新しいノードのみが子ノードを持ち、新しい子ノードを追加します createEle(vnode) // el の子 dom を作成します }else if (oldCh){ //古いノードのみがメモリ内に子ノードを持っているため、子ノードの削除操作を実行します api.removeChildren(el) } } } // 更新vnode:updateChildren function updateChildren (parentElm、oldCh、newCh、insertVnodeQueue、removeOnly) { var oldStartIdx = 0; var newStartIdx = 0; var oldEndIdx = oldCh.length - 1; var oldStartVnode = oldCh[0]; var oldEndVnode = oldCh[oldEndIdx]; var newEndIdx = newCh.length - 1; var newStartVnode = newCh[0]; var newEndVnode = newCh[newEndIdx]; var oldKeyToIdx、idxInOld、vnodeToMove、refElm; //removeOnly は、<transition-group> によってのみ使用される特別なフラグです。 // 削除された要素が正しい相対位置に留まるようにするため // 遷移終了時 var canMove = !removeOnly; { checkDuplicateKeys(newCh); } // インデックスが正常な場合 while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) { //現在開始されている古いノードが定義されていないため、次のノードを入力してください if (isUndef(oldStartVnode)) { oldStartVnode = oldCh[++oldStartIdx]; // Vnode が左に移動されました // 現在終了している古いノードが定義されていないため、前のノードを入力してください else if (isUndef(oldEndVnode)) { oldEndVnode = oldCh[--oldEndIdx]; // 古い開始ノードが新しい開始ノードと同じ場合、そのノードの更新を開始してから次のノードに進みます else if (sameVnode(oldStartVnode, newStartVnode)) { //ノードを更新する patchVnode(oldStartVnode、newStartVnode、insertVnodeQueue); oldStartVnode = oldCh[++oldStartIdx]; newStartVnode = newCh[++newStartIdx]; // 古い終了ノードが新しい終了ノードと同じ場合、そのノードの更新を開始してから次のノードに進みます else if (sameVnode(oldEndVnode, newEndVnode)) { patchVnode(oldEndVnode、newEndVnode、insertVnodeQueue); oldEndVnode = oldCh[--oldEndIdx]; newEndVnode = newCh[--newEndIdx]; // 古い開始ノードが新しい終了ノードと同じ場合、ノードを更新した後、古い開始ノードをノードの最後に移動します } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode が右に移動 patchVnode(oldStartVnode、newEndVnode、insertVnodeQueue); canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm)); oldStartVnode = oldCh[++oldStartIdx]; newEndVnode = newCh[--newEndIdx]; // 古い終了ノードが新しい開始ノードと同じ場合、ノードを更新した後、古い終了ノードをノードの先頭に移動します } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode が左に移動 patchVnode(oldEndVnode、newStartVnode、insertVnodeQueue); canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm); oldEndVnode = oldCh[--oldEndIdx]; newStartVnode = newCh[++newStartIdx]; } それ以外 { // 古いノードにキーが定義されていない場合は、キーを作成します if (isUndef(oldKeyToIdx)) { oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx); } idxInOld = isDef(newStartVnode.key) ? oldKeyToIdx[newStartVnode.key] : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx); // インデックスが定義されていない場合は、新しいノード要素を作成します if (isUndef(idxInOld)) { // 新しい要素 createElm(newStartVnode、insertVnodeQueue、parentElm、oldStartVnode.elm); } それ以外 { vnodeToMove = oldCh[idxInOld]; if (sameVnode(vnodeToMove, newStartVnode)) { patchVnode(vnodeToMove、newStartVnode、insertVnodeQueue); oldCh[idxInOld] = 未定義; canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm); } それ以外 { // キーは同じですが要素が異なります。新しい要素として扱う createElm(newStartVnode、insertVnodeQueue、parentElm、oldStartVnode.elm); } } newStartVnode = newCh[++newStartIdx]; } } // 古いノードの開始インデックスが終了インデックスより大きい場合は、新しいノードを作成し、新しい開始ノードのインデックスが新しい終了ノードより大きい場合は、古いノードを削除します。 if (oldStartIdx > oldEndIdx) { refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm; addVnodes(parentElm、refElm、newCh、newStartIdx、newEndIdx、insertVnodeQueue); else if (newStartIdx > newEndIdx) { RemoveVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx); } }
33. vuex ページを更新するとデータが失われますか? そしてヒストリーモードリフレッシュ404の問題?
// ページのロード時に sessionStorage 内のステータス情報を読み取ります if ( sessionStorage.getItem('state') ) { this.$store.replaceState( Object.assign( {}, this.$store.state, JSON.parse(sessionStorage.getItem('state') ) ) ) } // ページが更新されたときに状態データを sessionStorage に保存します window.addEventListener('beforeunload',()=>{ sessionStorage.setItem('state',JSON.stringify(this.$store.state) ) }) // ヒストリーモードリフレッシュ404問題はvue.config.jsで設定されています module.exports = { publicPath: '/', //これは必要です。静的リソースを導入するときは、ルート パスからインポートする必要があります。そうしないと、静的リソースが見つかりません。 開発サーバー: { // 履歴モードの URL がサーバーに要求されますが、サーバーにはこのリソース ファイルがなく、404 が返されるため、この項目を設定する必要があります。 履歴Apiフォールバック: { Index: '/index.html' //出力を含むpublicPath }、 }、 }
34. Vue開発でグローバル状態定数を使用するにはどうすればよいですか? このステータス定数は何に使用しますか?
たとえば、最も一般的なグローバル状態定数は process.env.NODE_ENV です。
可能な値は次のとおりです: 生産、開発
webpack.config.js のモードです。
{ モード: ""、 エントリ: ""、 出力: {} } // たとえば、現在開発モードにある場合、特定の機能ボタンを表示します。 <button v-if="プロセス.env.NODE_ENV === '開発'"> テストボタン </ボタン> このボタンは、npm runserve 時に表示されます。 npm run build 時にはこのボタンは表示されません
35. 動的ルーティング
addRoutes() を使用してルーティング情報を動的に追加します。