[Vue] Vue の超包括的な面接の質問

1.Vueについて理解していますか?

Vue.js (/vjuː/、または単に Vue) は、ユーザー インターフェイスを作成するためのオープン ソースの JavaScript フレームワークと、単一ページ アプリケーションを作成するための Web アプリケーション フレームワークです。

Vue は、ユーザー インターフェイスを構築するための先進的な MVVM フレームワークです。では、プログレッシブをどのように理解すればよいでしょうか?プログレッシブの意味: 最低限の必須のアサーション。

Vue.js には、宣言的レンダリング、コンポーネント化されたシステム、クライアント側ルーティング、大規模な状態管理、構築ツール、データ永続化、クロスプラットフォーム サポートなどが含まれています。ただし、実際の開発では、開発者に特定の機能の使用を強制するものではありません。が、ニーズに応じて徐々に拡張されました。

Vue の中心となるのは MVC パターンのビュー層ですが、同時にデータ更新を簡単に取得し、コンポーネント内の特定のメソッドを通じてビューとモデル間の対話を実現することもできます。

Vue.js のコア ライブラリはビューのレンダリングのみを考慮しており、その進歩的な性質により、Vue.js はサードパーティのライブラリや既存のプロジェクトと簡単に統合できます。Vue.js は、一連の宣言型レンダリング エンジンを実装し、実行時またはプリコンパイル時に宣言型テンプレートをレンダリング関数にコンパイルし、オブザーバーにマウントします。レンダリング関数 (タッチ) では、レスポンシブ システムは応答のゲッター メソッドを使用します。データはオブザーバーへの依存関係を収集し(Collect as dependency)、レスポンシブデータのsetterメソッドを使用してすべてのオブザーバーに更新を通知(通知)します。このとき、オブザーバーのWatcherはコンポーネントのレンダリング関数をトリガーします(Trigger re) -render). ) を実行すると、コンポーネントによって実行される render 関数によって新しい仮想 DOM ツリーが生成されますが、このとき、Vue は新旧の仮想 DOM ツリーを Diff して、操作が必要な実際の DOM を見つけて更新します。

2. Vue の双方向バインディングについて理解していますか?

Vue データの双方向バインディングとは、次の図に示すように、主にデータの変更によってビューが更新され、ビューの変更によってデータが更新されることを指します
ここに画像の説明を挿入します

  • 入力ボックスの内容が変更されると、同時に Data のデータも変更されます。それは View => Data の変更です。

  • Data 内のデータが変更されると、テキスト ノードの内容も同期して変更されます。つまり、データ => ビューの変更です。

このうち、View の変更による Data の更新はイベント リスニングを通じて実現できるため、Vue の双方向データ バインディングの作業は主に Data の変更に応じて View を更新する方法になります。

Vue は主に、次の 4 つの手順を通じて双方向データ バインディングを実装します。

  1. リスナー オブザーバーを実装します。サブプロパティ オブジェクトのプロパティを含むデータ オブジェクトを走査し、Object.defineProperty() を使用してプロパティにセッターとゲッターを追加します。この場合、このオブジェクトに値を割り当てるとセッターがトリガーされ、データの変更を監視できるようになります。
  2. パーサーの実装 コンパイル: Vue テンプレート命令を解析し、テンプレート内の変数をデータに置き換えてから、レンダリング ページ ビューを初期化し、更新関数を各命令に対応するノードにバインドし、データを監視するサブスクライバーを追加します。変更したり、通知を受け取ったり、更新関数を呼び出してデータを更新したりできます。
  3. サブスクライバー ウォッチャーの実装: ウォッチャー サブスクライバーは、オブザーバーとコンパイルの間の通信ブリッジです。その主なタスクは、オブザーバーで属性値変更のメッセージをサブスクライブすることです。属性値変更のメッセージを受信すると、パーサーのコンパイルで対応するメッセージが次のようになります。トリガーされた更新関数。
  4. サブスクライバ Dep を実装する: サブスクライバは、パブリッシュ/サブスクライブ設計パターンを採用して、サブスクライバ ウォッチャーを収集し、リスナー オブザーバーとサブスクライバ ウォッチャーを均一に管理します。

ここに画像の説明を挿入します

3.Vue の v-show と v-if の違いは何ですか?

v-if は、条件付きブロック内のイベント リスナーとサブコンポーネントが切り替え中に適切に破棄され再作成されることを保証するという点で、真の条件付きです。また、遅延型でもあります。最初のレンダリングで条件が false の場合、何も行いません - 条件付きブロックは初めて条件が true になるまでレンダリングは開始されません。

v-show ははるかに単純です。要素は初期条件に関係なく常にレンダリングされ、CSS の「表示」プロパティに基づいて単純に切り替えられます。

したがって、v-if は実行時に条件がほとんど変化せず、条件を頻繁に切り替える必要がないシナリオに適しており、v-show は条件を頻繁に切り替える必要があるシナリオに適しています。

4.Vue インスタンスのマウント プロセス中に何が起こりますか?

  • 新しい Vue を呼び出すと、_init メソッドが呼び出されます。

      定义 $set、 $get 、$delete、$watch 等方法
      定义 $on、$off、$emit、$off 等事件
      定义 _update、$forceUpdate、$destroy生命周期
      调用$mount进行页面的挂载
    
  • マウントする場合は、主に mountComponent メソッドを使用します。

  • updateComponent更新関数の定義

  • レンダリングを実行して仮想DOMを生成する

  • _update は、仮想 DOM から実際の DOM 構造を生成し、それをページにレンダリングします。

5. Vue のライフサイクルを理解していますか?

(1) ライフサイクルとは何ですか?

Vue インスタンスには完全なライフサイクルがあります。つまり、作成、データの初期化、テンプレートのコンパイル、Dom のマウント -> レンダリング、更新 -> レンダリング、アンインストールなどの一連のプロセスです。これを Vue のライフサイクルと呼びます。

(2) 各ライフサイクルの役割

ライフサイクル 説明する
作成前 コンポーネントインスタンスの作成時、コンポーネントのプロパティが有効になる前
作成した コンポーネントのインスタンスは完全に作成され、プロパティはバインドされましたが、実際の DOM はまだ生成されておらず、$el はまだ使用できません。
マウント前 マウントが開始される前に呼び出されます。関連するレンダリング関数が初めて呼び出されます。
取り付けられた el は新しく作成された vm.$el に置き換えられ、フックはインスタンスにマウントされた後に呼び出されます。
更新前 コンポーネント データが更新される前に呼び出され、仮想 DOM にパッチが適用される前に発生します。
アップデート コンポーネントデータ更新後
アクティブ化された キープアライブ排他的、コンポーネントがアクティブ化されたときに呼び出されます
無効化された キープアライブ排他的、コンポーネントが破棄されたときに呼び出されます
破壊前 コンポーネントが破棄される前に呼び出されます
破壊された コンポーネントが破棄された後に呼び出されます

(3) ライフサイクル図

ここに画像の説明を挿入します

6. SPA の最初の画面の読み込み速度が遅いことを解決するにはどうすればよいですか?

  • コード分​​割を使用する: コードを小さなチャンクに分割し、それらをオンデマンドで読み込み (遅延読み込み)、不要なネットワーク要求を回避し、読み込み時間を短縮します。
  • キャッシュ リソース: ブラウザーのキャッシュを活用して、CSS ファイルや JS ファイル、画像などの再利用ファイルを保存します。
  • キー リソースのプリロード: 最初のレンダリングの前に、ホームページに必要な JS、CSS、データなどのキー リソースが事前にロードされ、キー コンテンツの高速レンダリングが保証されます。
  • 適切な画像形式を使用する: 適切な画像形式 (JPEG、PNG、WebP など) を選択し、必要に応じて圧縮してファイル サイズを削減します。一部の小さなアイコンについては、代わりに iconfont などのフォント ファイルを使用できます。
  • Gzip 圧縮を有効にする: サーバー側の Gzip 圧縮アルゴリズムを使用してファイルを圧縮し、転送時間と帯域幅の消費を削減します。
  • CDN を使用する: コンテンツ配信ネットワーク (CDN) を使用してファイルをキャッシュして配信し、ファイルのダウンロード速度と信頼性を向上させます。
  • API リクエストの最適化: API 呼び出しの数を可能な限り減らし、キャッシュや遅延読み込みなどの手法を使用して API リクエストの効率を最適化します。
  • サーバー側レンダリングを使用する: サーバー側レンダリング (SSR) を使用して HTML を生成し、クライアント側レンダリングに必要な時間とリソースを削減します。ただし、SSR によりサーバーの負荷が増加し、Web サイトがより複雑になる可能性があることに注意することが重要です。

7.vue-routerのルーティングフック機能とは何ですか? 実行の順序は何ですか?

ルーティング フックの実行プロセス。フック関数の種類には、グローバル ガード、ルーティング ガード、コンポーネント ガードが含まれます。
完全なナビゲーション分析プロセス:
1. ナビゲーションがトリガーされます。
2. 非アクティブ化されたコンポーネントで beforeRouterLeave ガードを呼び出します。
3.Each ガードの前にグローバルを呼び出します。
4. 再利用されたコンポーネントで beforeRouterUpdate ガード (2.2 以降) を呼び出します。
5. beforeルーティング設定を入力します。
6. 非同期ルーティング コンポーネントを解析します。
7. アクティブ化されたコンポーネントで beforeRouterEnter を呼び出します。
8. グローバル beforeResolve ガード (2.5 以降) を呼び出します。
9. ナビゲーションが確認されました。
10. グローバルの afterEach フックを呼び出します。
11. DOM 更新をトリガーします。
12. beforeRouterEnter ガードで next に渡されたコールバック関数を呼び出します。作成されたコンポーネント インスタンスは、コールバック関数のパラメータとして渡されます。

8. Vue がオブジェクトに新しい属性を追加するときにインターフェイスが更新されない場合はどうすればよいですか?

Vue では、すでに作成されたインスタンスに新しいリアクティブ プロパティを動的に追加することはできません

データとビューを同期して更新する場合は、次の 3 つのソリューションを採用できます。

Vue.set()
Object.assign()
$forcecUpdated()

1. Vue.set()

Vue.set を通じて応答オブジェクトにプロパティを追加し、新しいプロパティも応答し、ビューの更新をトリガーすることを確認します。

function set (target: Array<any> | Object, key: any, val: any): any {
  ...
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val
}

これは、defineReactive メソッドを再度呼び出して、新しい属性の応答性を実装することに他なりません。

defineReactive メソッドに関しては、プロパティのインターセプトは引き続き Object.defineProperty を通じて内部的に実装されます。

おおよそのコードは次のとおりです。

function defineReactive(obj, key, val) {
    Object.defineProperty(obj, key, {
        get() {
            console.log(`get ${key}:${val}`);
            return val
        },
        set(newVal) {
            if (newVal !== val) {
                console.log(`set ${key}:${newVal}`);
                val = newVal
            }
        }
    })
}

2. Object.assign()

Object.assign() を使用してオブジェクトに新しいプロパティを直接追加しても、更新はトリガーされません

元のオブジェクトと混合オブジェクトのプロパティをマージして、新しいオブジェクトを作成する必要があります。

this.someObject = Object.assign({},this.someObject,{newProperty1:1,newProperty2:2 ...})

3. $forceUpdate

Vue で強制更新が必要になった場合は、99.9% の確率で、どこかで何か間違ったことをしていることになります。

$forceUpdate は Vue インスタンスを強制的に再レン​​ダリングします

PS: すべてのサブコンポーネントではなく、インスタンス自体とスロット コンテンツに挿入されたサブコンポーネントにのみ影響します。

まとめ

如果为对象添加少量的新属性,可以直接采用Vue.set()

如果需要为新对象添加大量的新属性,则通过Object.assign()创建新对象

如果你实在不知道怎么操作时,可采取$forceUpdate()进行强制刷新 (不建议)

PS: vue3 はデータ応答性を実現するためにプロキシを使用しますが、新しい属性を直接動的に追加してもデータ応答性を実現できます。

9.Vue での $nextTick の用途は何ですか?

効果:

Vue は DOM を非同期的に更新します。データが変更されても、DOM の更新はすぐには完了しません。nextTick コールバックは、次の DOM 更新サイクルが終了した後に実行される遅延コールバックです。

実装原則:

  • nextTickでは主にマクロタスクとマイクロタスクを使用します。実行環境に応じて Promise を使用してみてください。現在の関数呼び出しスタックの最後まで関数を遅らせることができます。

    MutationObserver: H5 で追加された新しい機能で、DOM ノードの変更を監視する機能です。

    変更が完了すると、コールバック関数 setImmediate が実行されます。これは、長時間実行される操作を中断し、ブラウザーが他の操作 (イベントや表示の更新など) を完了した直後にコールバック関数を実行するために使用されます。

    上記のいずれも機能しない場合は、setTimeout を使用して関数の DOM への送信を遅らせます。

    アップデート後、ご利用ください。その理由は、マイクロタスクよりもマクロタスクの方が消費量が多いためです。マイクロタスクが最初に使用され、最も消費量の多いマクロタスクが最後に使用されます。

10. スロットについてどのように理解していますか? そして、どのような応用シナリオがあるのでしょうか?

スロットとは何ですか

HTML では、Web コンポーネント テクノロジー スイートの一部としてのスロット要素は、Web コンポーネント内のプレースホルダーです。

このプレースホルダーは、独自のマークアップ言語を使用して後で入力できます。使用
シナリオにより
、ユーザーはスロットを介してコンポーネントを拡張し、コンポーネントをより適切に再利用してカスタマイズできます。

親コンポーネントが再利用されたコンポーネントを使用し、コンポーネントの別の場所で少量の変更を取得する場合、コンポーネントを書き直すのは賢明ではありません。

スロットを介してコンポーネント内の指定された場所にコンテンツを渡し、さまざまなシナリオでこの再利用可能なコンポーネントのアプリケーションを完了します。

たとえば、レイアウト コンポーネント、テーブル列、ドロップダウン選択、コンテンツを表示するポップアップ ボックスなどです。

3. 分類
スロットは次の 3 種類に分類できます。

默认插槽
具名插槽
作用域插槽

デフォルトのスロット
サブコンポーネントは、タグを使用してレンダリング位置を決定します。タグ内に DOM 構造を配置できます。スロットにコンテンツを渡さずに親コンポーネントを使用すると、タグ内の DOM 構造がページに表示されます。

親コンポーネントを使用する場合は、子コンポーネントのタグに直接コンテンツを記述するだけです。

子组件Child.vue

<template>
    <slot>
      <p>插槽后备的内容</p>
    </slot>
</template>

父组件
<Child>
  <div>默认插槽</div>  
</Child>

名前付きスロット
サブコンポーネントは、name 属性を使用してスロットの名前を表し、それをデフォルト スロットとして渡しません。

親コンポーネントを使用する場合は、デフォルトのスロットを基にスロット属性を追加し、その値が子コンポーネントのスロット名属性の値となります。

// 子组件Child.vue

<template>
    <slot>插槽后备的内容</slot>
  <slot name="content">插槽后备的内容</slot>
</template>

//父组件
<child>
    <template v-slot:default>具名插槽</template>
    <!-- 具名插槽⽤插槽名做参数 -->
    <template v-slot:content>内容...</template>
</child>

スコープ スロット
サブコンポーネントは、スコープ上のプロパティをバインドして、サブコンポーネント情報を親コンポーネントに渡して使用できるようにします。これらのプロパティは、親コンポーネントの v スロットによって受け入れられるオブジェクトにハングされます。

親コンポーネントでは、v-slot:(略称:#)を使用して子コンポーネントの情報を取得し、コンテンツ内で使用します。

子组件Child.vue
<template> 
  <slot name="footer" testProps="子组件的值">
          <h3>没传footer插槽</h3>
    </slot>
</template>

父组件
<child> 
    <!-- 把v-slot的值指定为作⽤域上下⽂对象 -->
    <template v-slot:default="slotProps">
      来⾃⼦组件数据:{
   
   {slotProps.testProps}}
    </template>
  <template #default="slotProps">
      来⾃⼦组件数据:{
   
   {slotProps.testProps}}
    </template>
</child>

まとめ:

v-slot属性只能在<template>上使用,但在只有默认插槽时可以在组件标签上使用

默认插槽名为default,可以省略default直接写v-slot

缩写为#时不能不写参数,写成#default

可以通过解构获取v-slot={user},还可以重命名v-slot="{user: newName}"和定义默认值v-slot="{user = '默认值'}"

11.Vue における mixin はどのようなものですか? そして、どのような応用シナリオがあるのでしょうか?

Vue の mixin の機能は、パブリック ビジネス ロジックを抽象化することです。原理はオブジェクトの継承に似ています。コンポーネントが初期化されると、マージするために mergeOptions メソッドが呼び出され、さまざまな属性をマージするためにストラテジー モードが使用されます。混合データが自身のコンポーネントのデータと矛盾する場合は、自身のデータが優先されます。

12. Vue コンポーネントとプラグインの違いは何ですか?

13.Vue.Observableとは何ですか?

Vue.observable はオブジェクトを応答性の高いデータに変換します。Vue はそれを内部で使用して、データ関数によって返されたオブジェクトを処理します。

返されたオブジェクトは、レンダリング関数および計算されたプロパティ内で直接使用でき、変更が発生すると対応する更新をトリガーします。最小化されたコンポーネント間の状態ストアとしても機能します

Vue.observable({ count : 1})

其作用等同于
new vue({ count : 1})

Vue 2.x では、渡されたオブジェクトは、返されたオブジェクトと同じオブジェクトである Vue.observable によって直接変更されます。

Vue 3.x では、応答するプロキシが返されますが、ソース オブジェクトへの直接の変更は依然として応答しません。

使用するシーン

親子以外のコンポーネント間で通信する場合は、通常のバスを使う方法とvuexを使う方法がありますが、実装されている機能はそれほど複雑ではなく、上の2つを使うのは少し面倒です。現時点では、observable が良い選択です

14.Vueのキーの原理は何ですか?

Vue では、キーは、Vue が仮想 DOM 内の変更を識別して追跡するのに役立つ特別な属性です。Vue は実際の DOM を更新してレンダリングするときに、key 属性を使用して古いノードと新しいノードを比較し、既存の実際の DOM ノードを可能な限り再利用してパフォーマンスを向上させます。

Vue が仮想 DOM の差分アルゴリズムを実行するとき、キーを使用して古いノードと新しいノードを照合し、ノードの更新、移動、または削除を決定します。key 属性を使用して、2 つのノードが内容が同じかどうかだけでなく、同じエンティティを表すかどうかを判断します。これにより、ノードの状態が保存され、不必要な DOM 操作が回避されます。

キーは次のように機能します。

Vue は実際の DOM を更新してレンダリングするときに、古いノードと新しいノードを比較してそれらの違いを見つけます。
2 つのノードが同じキー値を持つ場合、Vue はそれらを同じノードとみなし、既存の実際の DOM ノードを再利用しようとします。
ノードのキー値が異なる場合、Vue はそれらを別のノードとして扱い、適切に更新、移動、または削除します。
キーを使用すると、より正確なノードの識別と追跡が可能になり、要素のちらつきやリスト内の並べ替えによって発生する入力ボックスの内容の損失など、いくつかの一般的な問題を回避できます。

キーは一意で安定している必要があり、データの一意の ID などの一意の識別子を持つ値を使用することが最善です。同時に、乱数をキーとして使用することはお勧めできません。更新されるたびに新しいキーが生成され、すべてのノードが再レンダリングされ、既存のノードを再利用できなくなり、パフォーマンスが低下するためです。

より正確: キーの場合、インプレース再利用がないため、sameNode 関数 a.key === b.key の比較では、インプレース再利用を回避できます。したがって、より正確になります。

Faster : キーの一意性を利用してマップ オブジェクトを生成し、対応するノードを取得します。これはトラバーサル メソッドよりも高速です。ソース コードは次のとおりです。

function createKeyToOldIdx (children, beginIdx, endIdx) {
    
    
  let i, key
  const map = {
    
    }
  for (i = beginIdx; i <= endIdx; ++i) {
    
    
    key = children[i].key
    if (isDef(key)) map[key] = i
  }
  return map
}

15.Vue におけるキープアライブとはどのようなものですか?

keep-alive は Vue の組み込みコンポーネントであり、含まれているコンポーネントの状態を保持し、再レンダリングを回避できるようにします。

  • 通常、コンポーネントをキャッシュするためにルーティングおよび動的コンポーネントと組み合わせて使用​​されます。

  • include 属性と exclude 属性を指定します。どちらも文字列または正規表現をサポートします。include は名前が一致するコンポーネントのみがキャッシュされることを意味し、exclude は名前が一致するコンポーネントはキャッシュされないことを意味し、exclude は include より優先順位が高くなります。

  • 有効化と無効化の 2 つのフック機能に対応し、コンポーネントが有効化されると有効化されたフック機能がトリガーされ、コンポーネントが削除されると無効化されたフック機能がトリガーされます。

16.Axios は Vue にカプセル化されていますか?

17.Vueプロジェクトで構造とコンポーネントを分割するにはどうすればよいですか?

文件夹和文件夹内部文件的语义一致性
单一入口/出口
就近原则,紧耦合的文件应该放到一起,且应以相对路径引用
公共的文件应该以绝对路径的方式从根目录引用
/src 外的文件不应该被引入

18.Vue はどのように権限管理を実装しますか? ボタンレベルの権限を制御するにはどうすればよいですか?

フロントエンドの権限制御は、次の 4 つの側面に分類できます。

接口权限
按钮权限
菜单权限
路由权限

インターフェースの権限

現在、インターフェイスの権限は jwt 形式で検証されており、失敗した場合は通常 401 が返され、ログイン ページにジャンプして再度ログインします。

ログイン後、トークンを取得し、トークンを保存し、axios リクエスト インターセプターを通じてそれをインターセプトします。各リクエストのヘッダーにはトークンが含まれます。

axios.interceptors.request.use(config => {
    config.headers['token'] = cookie.get('token')
    return config
})
axios.interceptors.response.use(res=>{},{response}=>{
    if (response.data.code === 40099 || response.data.code === 40098) { //token过期或者错误
        router.push('/login')
    }
})

ルーティング許可制御

オプション 1

初期化とは、すべてのルートをマウントし、対応する許可情報をルートにマークし、ジャンプする前に各ルートを検証することを意味します。

const routerMap = [
  {
    
    
    path: '/permission',
    component: Layout,
    redirect: '/permission/index',
    alwaysShow: true, // will always show the root menu
    meta: {
    
    
      title: 'permission',
      icon: 'lock',
      roles: ['admin', 'editor'] // you can set roles in root nav
    },
    children: [{
    
    
      path: 'page',
      component: () => import('@/views/permission/page'),
      name: 'pagePermission',
      meta: {
    
    
        title: 'pagePermission',
        roles: ['admin'] // or you can only set roles in sub nav
      }
    }, {
    
    
      path: 'directive',
      component: () => import('@/views/permission/directive'),
      name: 'directivePermission',
      meta: {
    
    
        title: 'directivePermission'
        // if do not set roles, means: this page does not require permission
      }
    }]
  }]

このアプローチには次の 4 つの欠点があります。

加载所有的路由,如果路由很多,而用户并不是所有的路由都有权限访问,对性能会有影响。

全局路由守卫里,每次路由跳转都要做权限判断。

菜单信息写死在前端,要改个显示文字或权限信息,需要重新编译

菜单跟路由耦合在一起,定义路由的时候还有添加菜单显示标题,图标之类的信息,而且路由不一定作为菜单显示,还要多加字段进行标识

オプション II

初期化中に、まず、ログイン ページ、404、その他のエラー ページなど、権限制御を必要としないルートをマウントします。ユーザーが URL 経由で強制アクセスを実行すると、直接 404 に入ります。これはソースを制御することと同等です。

ログイン後、ユーザーの権限情報を取得し、アクセス権限のあるルートをフィルタリングし、グローバルルーティングガードのaddRoutesを呼び出してルートを追加します。

import router from './router'
import store from './store'
import {
    
     Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css'// progress bar style
import {
    
     getToken } from '@/utils/auth' // getToken from cookie

NProgress.configure({
    
     showSpinner: false })// NProgress Configuration

// permission judge function
function hasPermission(roles, permissionRoles) {
    
    
  if (roles.indexOf('admin') >= 0) return true // admin permission passed directly
  if (!permissionRoles) return true
  return roles.some(role => permissionRoles.indexOf(role) >= 0)
}

const whiteList = ['/login', '/authredirect']// no redirect whitelist

router.beforeEach((to, from, next) => {
    
    
  NProgress.start() // start progress bar
  if (getToken()) {
    
     // determine if there has token
    /* has token*/
    if (to.path === '/login') {
    
    
      next({
    
     path: '/' })
      NProgress.done() // if current page is dashboard will not trigger    afterEach hook, so manually handle it
    } else {
    
    
      if (store.getters.roles.length === 0) {
    
     // 判断当前用户是否已拉取完user_info信息
        store.dispatch('GetUserInfo').then(res => {
    
     // 拉取user_info
          const roles = res.data.roles // note: roles must be a array! such as: ['editor','develop']
          store.dispatch('GenerateRoutes', {
    
     roles }).then(() => {
    
     // 根据roles权限生成可访问的路由表
            router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
            next({
    
     ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
          })
        }).catch((err) => {
    
    
          store.dispatch('FedLogOut').then(() => {
    
    
            Message.error(err || 'Verification failed, please login again')
            next({
    
     path: '/' })
          })
        })
      } else {
    
    
        // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
        if (hasPermission(store.getters.roles, to.meta.roles)) {
    
    
          next()//
        } else {
    
    
          next({
    
     path: '/401', replace: true, query: {
    
     noGoBack: true }})
        }
        // 可删 ↑
      }
    }
  } else {
    
    
    /* has no token*/
    if (whiteList.indexOf(to.path) !== -1) {
    
     // 在免登录白名单,直接进入
      next()
    } else {
    
    
      next('/login') // 否则全部重定向到登录页
      NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
    }
  }
})

router.afterEach(() => {
    
    
  NProgress.done() // finish progress bar
})

オンデマンドでマウントするには、ルーティングはユーザーのルーティング権限を知る必要があります。つまり、ユーザーはログイン時に、現在のユーザーがどのようなルーティング権限を持っているかを知る必要があります。

この方法には次のような欠点もあります。

全局路由守卫里,每次路由跳转都要做判断

菜单信息写死在前端,要改个显示文字或权限信息,需要重新编译

菜单跟路由耦合在一起,定义路由的时候还有添加菜单显示标题,图标之类的信息,而且路由不一定作为菜单显示,还要多加字段进行标识

メニューの権限

メニューの権限は、ページを理由から切り離すものとして理解できます。

オプション 1

メニューはルーティングから分離され、メニューはバックエンドによって返されます。

フロントエンドはルーティング情報を定義します

{
    
    
    name: "login",
    path: "/login",
    component: () => import("@/pages/Login.vue")
}

名前フィールドが空ではありません。このフィールドはバックエンドの戻りメニューに関連付ける必要があります。バックエンドによって返されるメニュー情報には、名前に対応するフィールドがあり、一意性検証を実行する必要があります。

グローバルルーティングガードで判断する

function hasPermission(router, accessMenu) {
    
    
  if (whiteList.indexOf(router.path) !== -1) {
    
    
    return true;
  }
  let menu = Util.getMenuByName(router.name, accessMenu);
  if (menu.name) {
    
    
    return true;
  }
  return false;

}

Router.beforeEach(async (to, from, next) => {
    
    
  if (getToken()) {
    
    
    let userInfo = store.state.user.userInfo;
    if (!userInfo.name) {
    
    
      try {
    
    
        await store.dispatch("GetUserInfo")
        await store.dispatch('updateAccessMenu')
        if (to.path === '/login') {
    
    
          next({
    
     name: 'home_index' })
        } else {
    
    
          //Util.toDefaultPage([...routers], to.name, router, next);
          next({
    
     ...to, replace: true })//菜单权限更新完成,重新进一次当前路由
        }
      }  
      catch (e) {
    
    
        if (whiteList.indexOf(to.path) !== -1) {
    
     // 在免登录白名单,直接进入
          next()
        } else {
    
    
          next('/login')
        }
      }
    } else {
    
    
      if (to.path === '/login') {
    
    
        next({
    
     name: 'home_index' })
      } else {
    
    
        if (hasPermission(to, store.getters.accessMenu)) {
    
    
          Util.toDefaultPage(store.getters.accessMenu,to, routes, next);
        } else {
    
    
          next({
    
     path: '/403',replace:true })
        }
      }
    }
  } else {
    
    
    if (whiteList.indexOf(to.path) !== -1) {
    
     // 在免登录白名单,直接进入
      next()
    } else {
    
    
      next('/login')
    }
  }
  let menu = Util.getMenuByName(to.name, store.getters.accessMenu);
  Util.title(menu.title);
});

Router.afterEach((to) => {
    
    
  window.scrollTo(0, 0);
});

ルートがジャンプするたびに権限を判定する必要がありますが、メニュー名とルート名は1対1に対応しており、バックエンドから返されるメニューはすでにフィルタリングされているため、この判定も非常に簡単です。許可により。

ルート名に基づいて対応するメニューが見つからない場合は、ユーザーにアクセス権限がないことを意味します。

ルートが多数ある場合は、アプリケーションの初期化中に権限制御を必要としないルートのみをマウントできます。バックエンドから返されたメニューを取得した後、メニューとルートの対応関係に基づいて、アクセス可能なルートが除外され、addRoutes を通じて動的にマウントされます。

このアプローチの欠点は次のとおりです。

菜单需要与路由做一一对应,前端添加了新功能,需要通过菜单管理功能添加新的菜单,如果菜单配置的不对会导致应用不能正常使用

全局路由守卫里,每次路由跳转都要做判断

オプション II

メニューとルートの両方がバックエンドによって返されます

ルーティングコンポーネントのフロントエンドの統一定義

const Home = () => import("../pages/Home.vue");
const UserInfo = () => import("../pages/UserInfo.vue");
export default {
    
    
    home: Home,
    userInfo: UserInfo
};
后端路由组件返回以下格式

[
    {
    
    
        name: "home",
        path: "/",
        component: "home"
    },
    {
    
    
        name: "home",
        path: "/userinfo",
        component: "userInfo"
    }
]

addRoutes を通じてバックエンド リターン ルートを動的にマウントする前に、データを処理し、コンポーネント フィールドを実際のコンポーネントに置き換える必要があります。

ネストされたルートがある場合、バックエンド関数を設計するときは、対応するフィールドの追加に注意する必要があり、フロントエンドもデータを取得したときにそれに応じて処理する必要があります。

このアプローチには欠点もあります。

全局路由守卫里,每次路由跳转都要做判断
前后端的配合要求更高

ボタンの権限

オプション 1

ボタンの権限は v-if を使用して決定することもできます

ただし、ページ数が多すぎる場合は、各ページがルーティング テーブルのユーザー権限ロールとmeta.btnPermissionsを取得して判断する必要があります。

このように例は出しません。

オプション II

カスタム命令を通じてボタンの権限を決定する

首先配置路由

{
    
    
    path: '/permission',
    component: Layout,
    name: '权限测试',
    meta: {
    
    
        btnPermissions: ['admin', 'supper', 'normal']
    },
    //页面需要的权限
    children: [{
    
    
        path: 'supper',
        component: _import('system/supper'),
        name: '权限测试页',
        meta: {
    
    
            btnPermissions: ['admin', 'supper']
        } //页面需要的权限
    },
    {
    
    
        path: 'normal',
        component: _import('system/normal'),
        name: '权限测试页',
        meta: {
    
    
            btnPermissions: ['admin']
        } //页面需要的权限
    }]
}
自定义权限鉴定指令

import Vue from 'vue'
/**权限指令**/
const has = Vue.directive('has', {
    
    
    bind: function (el, binding, vnode) {
    
    
        // 获取页面按钮权限
        let btnPermissionsArr = [];
        if(binding.value){
    
    
            // 如果指令传值,获取指令参数,根据指令参数和当前登录人按钮权限做比较。
            btnPermissionsArr = Array.of(binding.value);
        }else{
    
    
            // 否则获取路由中的参数,根据路由的btnPermissionsArr和当前登录人按钮权限做比较。
            btnPermissionsArr = vnode.context.$route.meta.btnPermissions;
        }
        if (!Vue.prototype.$_has(btnPermissionsArr)) {
    
    
            el.parentNode.removeChild(el);
        }
    }
});
// 权限检查方法
Vue.prototype.$_has = function (value) {
    
    
    let isExist = false;
    // 获取用户按钮权限
    let btnPermissionsStr = sessionStorage.getItem("btnPermissions");
    if (btnPermissionsStr == undefined || btnPermissionsStr == null) {
    
    
        return false;
    }
    if (value.indexOf(btnPermissionsStr) > -1) {
    
    
        isExist = true;
    }
    return isExist;
};
export {
    
    has}

使用するボタンで v-has ディレクティブを引用するだけで済みます。

<el-button @click='editClick' type="primary" v-has>编辑</el-button>

19.Vue はクロスドメインの問題をどのように解決しますか?

JSONP

コルス

CORS (Cross-Origin Resource Sharing) は、ブラウザーがフロントエンド JavaScript コードによるクロスオリジン要求への応答の取得をブロックするかどうかを決定する、送信される一連の HTTP ヘッダーで構成されるシステムです。

CORS は実装が非常に便利で、いくつかの HTTP ヘッダーを追加するだけで、サーバーが許可されたアクセス ソースを宣言できるようになります。

バックエンドが CORS を実装している限り、クロスドメイン

プロキシ

プロキシ (ネットワーク プロキシとも呼ばれる) は、(通常はクライアント) がこのサービスを通じて別のネットワーク端末 (通常はサーバー) と間接的に接続できるようにする特別なネットワーク サービスです。ゲートウェイやルーターなどの一部のネットワークデバイスには、ネットワークプロキシ機能があります。一般に、プロキシ サービスは、ネットワーク端末のプライバシーやセキュリティを確保し、攻撃を防ぐのに役立つと考えられています。

リクエストはこのサーバーを介してターゲット サーバーに転送され、結果はフロントエンドに転送されますが、最終リリースの起動時に Web アプリケーションとインターフェイス サーバーが連携していない場合、ドメインをまたぐことになります。

module.exports = {
    
    
    devServer: {
    
    
        host: '127.0.0.1',
        port: 8084,
        open: true,// vue项目启动时自动打开浏览器
        proxy: {
    
    
            '/api': {
    
     // '/api'是代理标识,用于告诉node,url前面是/api的就是使用代理的
                target: "http://xxx.xxx.xx.xx:8080", //目标地址,一般是指后台服务器地址
                changeOrigin: true, //是否跨域
                pathRewrite: {
    
     // pathRewrite 的作用是把实际Request Url中的'/api'用""代替
                    '^/api': "" 
                }
            }
        }
    }
}

20. Vue プロジェクトのエラーにどう対処するか?

  • handleError は、例外をキャッチする必要がある場合に呼び出されます。まず、エラーを報告したコンポーネントが取得され、次に、現在のコンポーネントの親コンポーネントが再帰的に検索され、errorCaptured メソッドが順番に呼び出されます。すべての errorCaptured メソッドが走査された後、呼び出されるか、errorCaptured メソッドでエラーが報告されると、globalHandleError メソッドが呼び出されます。
  • globalHandleError は、グローバル errorHandler メソッドを呼び出し、logError を使用してエラー情報を出力する環境を決定します。
  • invokeWithErrorHandling は非同期エラー メッセージをより適切に処理します
  • logError は環境を決定し、さまざまなエラースロー方法を選択します。非運用環境では、warn メソッドを呼び出してエラーを処理します。

21. vue-router 動的ルーティングとは何ですか? 何が問題ですか。

多くの場合、特定のパターンに一致するすべてのルートを同じコンポーネントにマップする必要があります。たとえば、
異なる ID を持つすべてのユーザーをレンダリングするために使用する必要がある User コンポーネントがあります。次に、vue-router のルーティング パスで「動的パス パラメーター」(動的セグメント) を使用して、この効果を実現できます。

 const User = {
    
    
  template: " User", 
  };
 const router = new VueRouter({
    
    
 routes: [
 	// 动态路径参数 以冒号开头
 	{
    
     path: "/user/:id", component: User },
 ],
 });

質問: vue-router コンポーネントの再利用によりルーティング パラメータが無効になった場合はどうすればよいですか?

解決策:
1. ウォッチを通じてルーティング パラメータを監視し、リクエストを送信します。

 watch:{
    
    
 "router":function(){
    
    
	this.getData(this.$router.params.xxx)
 }
}

2. Use:key を使用して再利用を防止します

ルータービュー:key=“$route.fullPath”

22. Vue3 のパフォーマンス向上は主にどのような点に反映されますか?

Vue 3.0 のリリースが進行中です. Vue 3.0 の目標は、Vue コアをより小さく、より速く、より強力にすることです. そのため、Vue 3.0 には次の新機能が追加されています: (1) 監視メカニズムの
変更

  • 3.0 では、プロキシ Proxy に基づいたオブザーバー実装が導入され、完全な言語をカバーするリアクティブな追跡が提供されます。これにより、Vue 2 の Object.defineProperty ベースの実装の多くの制限が解消されます。監視できるのはプロパティのみであり、オブジェクトは監視できません。

    属性の追加と削除を検出します。

    配列のインデックスと長さの変更を検出します。

    Map、Set、WeakMap、WeakSet をサポートします。

    新しいオブザーバーは、次の機能も提供します。
    オブザーバブルを作成するためのパブリック API。これにより、小規模から中規模のシナリオ向けに、シンプルで軽量なクロスコンポーネント状態管理ソリューションが提供されます。

    遅延観察はデフォルトで使用されます。2.x では、リアクティブ データは、そのサイズに関係なく、起動時に観察されます。データセットが大きい場合、アプリケーションの起動時に顕著なオーバーヘッドが発生する可能性があります。3.xでは
    、アプリケーションの最初に表示される部分をレンダリングするために使用されるデータのみが監視されます。

    より正確な変更通知。2.x では、Vue.set 経由で新しいプロパティを強制すると、そのオブジェクトに依存するウォッチャーに変更が通知されます。3.x では
    、特定のプロパティに依存するウォッチャーのみが通知を受け取ります。

    不変のオブザーバブル: システムが内部で値を一時的に「ブロック解除」しない限り、値の「不変」バージョン (ネストされたプロパティでも) を作成できます。このメカニズムを使用すると、
    Vuex ステート ツリーの外部で prop パスや変更をフリーズすることができます。

    より良いデバッグ機能: 新しい renderTracked フックと renderTriggered
    フックを使用して、コンポーネントがいつ、そしてなぜ再レンダリングされるかを正確に追跡できます。

(2) テンプレート

  • テンプレートには大きな変更はなく、スコープ スロットのみが変更されます。2.x のメカニズムではスコープ スロットが変更され、親コンポーネントが再レンダリングされますが、3.0 ではスコープ スロットが関数に変更されるため、これはサブコンポーネントの再レンダリングに影響し、レンダリングのパフォーマンスが向上します。同時に、vue3.0 では、レンダリング関数に関して、
    API を直接使用して vdom を生成する習慣を促進する一連の変更も加えられます。

(3) オブジェクト形式のコンポーネント宣言方法

  • vue2.x のコンポーネントは一連のオプションを宣言で渡しており、
    TypeScript との組み合わせはいくつかのデコレータを介して行う必要があり、機能は実現できますが、面倒です。
    3.0ではコンポーネントの宣言方法がクラス記述方法に変更され、TypeScriptとの統合が容易になりました。また、vueのソースコードもTypeScriptで書かれています。実際、コードの機能が複雑な場合、補助的な管理を行うために静的型システムが必要になります。現在、vue3.0 は TypeScript で完全に書き直されており
    、TypeScript と外部公開 API を簡単に組み合わせることができるようになりました。静的型システムは、複雑なコードの保守には確かに必要です。

(4) その他の変更点

  • vue3.0 での変更点は包括的です。上記には主な 3 つの側面のみが含まれており、他にもいくつかの変更があります: カスタム レンダラーをサポートし、直接フォークする代わりにカスタム レンダラーによって weex を拡張できるようにする ソース コードの変更方法

    フラグメント (複数のルート ノード) およびポータル (dom の他の部分にコンポーネント コンテンツをレンダリング) コンポーネントをサポートし、いくつかの特殊なシナリオを処理します。

    ツリーシェイク最適化に基づいて、より多くの組み込み関数が提供されます。

23.Vuex ページが更新されたときにデータが失われる問題を解決するにはどうすればよいですか?

Vuex データの永続性が必要です。一般に、データの保存にはローカル ストレージ ソリューションが使用されます。ストレージ ソリューションは自分で設計することも、サードパーティのプラグインを使用することもできます。

Vuex 永続ストレージ用のプラグインである vuex-persist プラグインを使用することをお勧めします。

手動でストレージにアクセスする必要はありませんが、状態を Cookie または localStorage に直接保存します。

24.V3 のコンポジション API と V2 で使用されるオプション API の違いは何ですか?

  • 論理構成とロジックの再利用という点では、コンポジション API はオプション API よりも優れています
  • 構成 API はほぼ関数であるため、より適切な型推論が行われます。
  • Comboposition API はツリーシェイキングに適しており、コードの圧縮が容易です。
  • これの使用は、Composition API では確認できないため、これが未知のオブジェクトを指す状況が減少します。
  • 小さなコンポーネントの場合は、引き続き非常に使いやすいオプション API を使用できます。

25.$attrs はどのような問題を解決すると思われますか?

主な機能はデータをバッチで転送することです。

Provide/inject は、主にクロスレベルのデータ転送を実現するためのプラグインでのアプリケーションに適しています。

26. Vue3 でモデルを設計しますか?

27.Vuex とは何ですか? プロパティはいくつあり、それらの意味は何ですか?

Vuex は、Vue.js アプリケーション専用に開発された状態管理パターンです。すべての Vuex アプリケーションの中核はストアです。「ストア」は基本的に、アプリケーション内のほとんどの状態を含むコンテナーです。

(1) Vuex の状態ストレージは応答性があります。Vue コンポーネントがストアから状態を読み取るときに、ストア内の状態が変化すると、それに応じて対応するコンポーネントが効率的に更新されます。

(2) ストア内の状態を変更する唯一の方法は、ミューテーションを明示的に送信することです。これにより、あらゆる状態変化を簡単に追跡できるようになります。

主に次のモジュールが含まれています。

  • 状態: アプリケーション状態のデータ構造を定義します。デフォルトの初期状態をここで設定できます。
  • Getter: コンポーネントがストアからデータを取得できるようにします。mapGetters 補助関数は、ストア内のゲッターをローカルの計算されたプロパティにマップするだけです。
  • Mutation: ストア内の状態を変更する唯一のメソッドであり、同期関数である必要があります。
  • アクション: 状態を直接変更するのではなく、変更を送信するために使用され、非同期操作を含めることができます。
  • モジュール: 1 つのストアを複数のストアに分割し、同時に 1 つの状態ツリーに保存できます。

28.Vue SSRを使ったことがありますか? SSRの話?どうやって達成するのか?

Vue.js は、クライアント側アプリケーションを構築するためのフレームワークです。デフォルトでは、Vue コンポーネントをブラウザ上に出力して DOM を生成し、DOM を操作できます。ただし、同じコンポーネントをサーバー側で HTML 文字列としてレンダリングし、ブラウザに直接送信し、最終的にこれらの静的タグをクライアント上で完全に対話型のアプリケーションに「アクティブ化」することもできます。
SSR とは、大まかに言うと、Vue がクライアント上でタグをレンダリングする HTML フラグメント全体がサーバー上で完了し、サーバー上で形成された HTML フラグメントが直接クライアントに返されることを意味します。このプロセスはサーバーサイド レンダリングと呼ばれます。

サーバーサイドレンダリング SSR の利点と欠点は次のとおりです。
(1)サーバーサイドレンダリングの利点:

SEO の向上: SPA ページのコンテンツは Ajax を通じて取得され、検索エンジン クロール ツールはページ コンテンツをクロールする前に Ajax が非同期で完了するのを待たないため、Ajax を通じて取得したページは SPA でクロールできません。 ; SSR はレンダリングされたページをサーバーから直接返します (データはすでにページに含まれています)。そのため、検索エンジン クロール ツールはレンダリングされたページをクロールできます。

コンテンツの到着時間の短縮 (最初の画面の読み込みの高速化): SPA は、ページのレンダリングを開始する前に、Vue でコンパイルされたすべての js ファイルがダウンロードされるのを待ちます。ファイルのダウンロードには一定の時間がかかるため、最初の画面のレンダリングが遅くなります。一定の時間が必要です。SSR はサーバーからページを直接レンダリングし、それをディスプレイに直接返します。js ファイルをダウンロードして再度レンダリングするのを待つ必要がないため、SSR はコンテンツの到着時間が速くなります。

(2)サーバーサイドレンダリングのデメリット:

開発上の制限の追加: たとえば、サーバーサイド レンダリングでは、beforeCreate と created の 2 つのフック関数のみがサポートされるため、一部の外部拡張ライブラリはサーバーサイド レンダリング アプリケーションで実行する前に特別な処理が必要になり、任意の静的ファイルにデプロイできます。サーバー上の完全に静的なシングルページ アプリケーション SPA とは異なり、サーバー側レンダリング アプリケーションは Node.js サーバー実行環境にある必要があります。

サーバー負荷の増加: Node.js で完全なアプリケーションをレンダリングすると、静的ファイルを提供するだけのサーバーよりも明らかに CPU の使用量が多くなります。そのため、高トラフィック環境 (高トラフィック) での実行が予想される場合は、それに応じてサーバー負荷を準備してください。そしてキャッシュ戦略を賢明に採用してください。

29.Vuex補助機能の使い方は?

30. vue-loader は何をしますか?

vue-loader を使用する前に、必要なローダーをいくつかインストールする必要があります。

必要なローダーには、vue-loader、vue-style-loader、vue-template-compiler、css-loader が含まれます。考えられるローダーには、sass-loader、less-loader、url-loader などが含まれます。

vue-loader の仕組み

vue-loader を介して、webpack は .vue ファイルをブラウザで認識できる JavaScript に変換できます。

vue-loader のワークフローは、簡単に言うと次のステップに分かれています。

将一个 .vue 文件 切割成 template、script、styles 三个部分。

template 部分 通过 compile 生成 render、 staticRenderFns。

获取 script 部分 返回的配置项对象 scriptExports。

styles 部分,会通过 css-loader、vue-style-loader, 添加到 head 中, 或者通过 css-loader、MiniCssExtractPlugin 提取到一个 公共的css文件 中。

使用 vue-loader 提供的 normalizeComponent 方法, 合并 scriptExports、render、staticRenderFns, 返回 构建vue组件需要的配置项对象 - options, 即 **{data, props, methods, render, staticRenderFns...}**。

31.計算されたキャッシュはどのように実装されますか?

  1. データと計算結果を初期化し、それらの set メソッドと get メソッドをそれぞれプロキシし、データ内のすべての属性に対して一意の dep インスタンスを生成します。
  2. computed の合計に対する固有のウォッチャーを生成し、vm._computedWatchers に保存します。
  3. render 関数が実行されると sum 属性がアクセスされるため、initComputed の実行時に定義された getter メソッドが Dep.target を sum のウォッチャーにポイントし、この属性の特定のメソッド sum が呼び出されます。
  4. sum メソッドで this.count にアクセスすると、this.count エージェントの get メソッドが呼び出され、this.count の dep が sum のウォッチャーに追加され、dep 内の subs がこのウォッチャーを追加します。
  5. vm.count = 2 に設定し、count エージェントの set メソッドを呼び出して dep の通知メソッドをトリガーします。これは計算された属性であるため、ウォッチャーのダーティを true に設定するだけです。
  6. vm.sum の最後のステップでは、get メソッドにアクセスすると、sum の watcher.dirty が true であることがわかり、新しい値を取得するために watcher.evaluate() メソッドが呼び出されます。

32. vue の計算と監視の違いは何ですか?

computed: 他の属性値に依存する計算属性であり、計算値はキャッシュされます。依存する属性値が変更された場合にのみ、次回計算値を取得するときに計算値が再計算されます。

watch: これは、特定のデータの監視コールバックに似た「監視」関数であり、監視対象のデータが変更されるたびに、後続の操作のためにコールバックが実行されます。

アプリケーションシナリオ:

数値計算を実行する必要があり、他のデータに依存する場合は、computed を使用する必要があります。これは、computed のキャッシュ機能を使用して、値が取得されるたびに再計算することを避けることができるためです。

Watch は、データ変更時に非同期操作や高コストの操作を実行する必要がある場合に使用する必要があります。watch オプションを使用すると、非同期操作 (API にアクセス) を実行し、操作の実行頻度を制限し、最終結果が得られるまで待つことができます。 . 、中間状態を設定します。これらは、計算されたプロパティでは実行できないことです。

33.Vueページのレンダリングプロセス?

34.なぜ Vue2 は配列の変更をチェックできないのですか? の解き方?

35.Vnodeにはどのようなプロパティがありますか?

Vue によって内部的に定義された Vnode オブジェクトには、次のプロパティが含まれています。

  • __v_isVNode: true、内部属性、この属性は Vnode として表されます
  • __v_skip: true、内部属性、リアクティブ変換をスキップすることを示し、リアクティブ変換はこの属性に基づいて判断されます。
  • isCompatRoot?: true、互換性処理が行われたかどうかを判断するために使用されます。
  • type: VNodeTypes、仮想ノードのタイプ
  • props: (VNodeProps &ExtraProps) | null、仮想ノードの小道具
  • key: 文字列 | 数値 |null、仮想ステージのキーは diff に使用できます。
  • 参照: VNodeNormalizedRef | null、仮想ステージへの参照
  • scopeId: string | null、SFC (単一ファイル コンポーネント) の場合のみ、currentRenderingInstance を現在のレンダリング インスタンスに設定する場合、1 つのフェーズで設定されます
  • slotScopeIds: string[] | null、単一ファイル コンポーネントに限定、単一ファイル コンポーネントのスロットに関連
  • Children:VNodeNormalizedChildren、子ノード
  • コンポーネント: ComponentInternalInstance |null、コンポーネント インスタンス
  • dirs: DirectiveBinding[] | null、現在の Vnode にバインドされた命令
  • トランジション:トランジションフック | null,トランジションフック
  • DOM 関連のプロパティ

el: HostNode | null, ホスト ステージ
アンカー: HostNode | null // フラグメント アンカー
target: HostElement | null、テレポート ターゲットの送信ターゲット
targetAnchor: HostNode | null // テレポート ターゲットのアンカー
staticCount: 数値、含まれる静的ノードの数

サスペンス サスペンス関連のプロパティ
サスペンス: SuspenseBoundary | null
ssContent: VNode | null
ssFallback: VNode | null

最適化のみ 最適化に使用されるプロパティ
shapeFlag: 数値
patchFlag: 数値
dynamicProps: string[] | null
DynamicChildren: VNode[] | null

ルート ノードには属性
appContext があります: AppContext | null、インスタンス コンテキスト
Vue 内には、Vnode 記述オブジェクトに約 20 の属性があることがわかります。

閉鎖的になりすぎずにユーザーの負担を軽減するために、Vue はレンダリング h を作成しました。対応する Vnode は、ユーザーが必要なときに h 関数を通じて作成できます。

これにより、一部の上級プレイヤーが自由にプレイできる余地が残されています。

36.Vue ルーティングでは、ハッシュ モードとヒストリー モードの違いは何ですか?

(1) ハッシュモードの実装原理

フロントエンド ルーティングの初期の実装は location.hash に基づいていました。実装原理は非常にシンプルで、location.hash の値は URL の # 以降の内容になります。たとえば、次の Web サイトの location.hash 値は「#search」です。

https://www.word.com#search

ハッシュ ルーティング モードの実装は、主に次の機能に基づいています。

  • URL のハッシュ値はクライアントの状態だけを表します。つまり、サーバーにリクエストが行われたとき、ハッシュ部分は送信されません。

  • ハッシュ値が変更されると、ブラウザのアクセス履歴に記録が追加されます。したがって、ブラウザの「戻る」ボタンと「進む」ボタンを使用してハッシュの切り替えを制御できます。

  • a タグを渡して href 属性を設定できます。ユーザーがこのタグをクリックすると、URL のハッシュ値が変更されます。または、JavaScript を使用して loaction.hash に値を割り当て、URL のハッシュ値を変更できます。

  • hashchange イベントを使用してハッシュ値の変更をリッスンし、ページをジャンプ (レンダリング) できます。

(2) ヒストリーモードの実装原理

HTML5 は、URL の変更を実装するための History API を提供します。その中で、最も重要な 2 つの API は、history.pushState() とhistory.repalceState() です。これら 2 つの API は、ブラウザの履歴を更新せずに操作できます。
唯一の違いは、以下に示すように、前者は新しい履歴レコードを追加するのに対し、後者は現在の履歴レコードを直接置き換えることです。

window.history.pushState(null, null, path);
window.history.replaceState(null, null, path);

履歴ルーティング モードの実装は、主に次の機能に基づいています。

  • URL の変更を操作および実装するには、pushState と repalceState という 2 つの API があります。

  • Popstate イベントを使用して URL の変更を監視し、ページをジャンプ (レンダリング) することができます。

  • history.pushState() またはhistory.replaceState() は、popstate イベントをトリガーしません。この場合、ページ ジャンプ (レンダリング) を手動でトリガーする必要があります。

37.Vue 2/3 レスポンシブデザインの原則?

v2

全体的なアイデアは、データ ハイジャック + オブザーバー モードです。Vue
がデータを初期化するとき、Object.defineProperty を使用してデータ内のすべてのプロパティを再定義します。ページが対応するプロパティを使用するとき、最初に依存関係の収集 (現在のウォッチャーを収集) を実行します。プロパティ Changes が更新操作 (パブリッシュおよびサブスクライブ) の関連する依存関係に通知する場合

Vue2.x は、パブリッシュ/サブスクライブ モード (PubSub モード) と組み合わせたデータ ハイジャックを使用して、Object.defineProperty を通じて各プロパティのセッターとゲッターをハイジャックします。データが変更されると、サブスクライバーにメッセージをパブリッシュし、対応するリスニング コールバックをトリガーします。

プレーンな Javascript オブジェクトをデータ オプションとして Vue インスタンスに渡すと、Vue はそのプロパティを反復処理し、Object.defineProperty を使用してプロパティをゲッター/セッターに変換します。ゲッター/セッターはユーザーには表示されませんが、内部的には Vue が依存関係を追跡し、プロパティがアクセスされ変更されたときに変更を通知することができます。

Vue の双方向データ バインディングは、Observer、Compile、Watcher を統合します。Observer は、独自のモデルのデータ変更を監視するために使用されます。Compile は、テンプレート命令の解析とコンパイルに使用されます。最後に、Watcher は、Observer と Compile の間の通信ブリッジを構築するために使用されます。データ変更 -> 更新の表示、対話型変更 (入力操作など) の表示 -> データ モデル変更の双方向バインディング効果を実現します。

v3

プロキシはオブジェクトの最初のレイヤーのみをプロキシしますが、Vue3 はこの問題にどのように対処しますか?
配列を監視する場合、get/set が複数回トリガーされる可能性があります。複数のトリガーを防ぐにはどうすればよいでしょうか?

参考回答:Vue3.xのレスポンシブデータの原理は何ですか?Vue 2 では、応答原則は Object.defineProperty を使用して実装されます。ただし、Vue 3.0 では Proxy が採用され、Object.defineProperty メソッドは廃止されました。
理由は主に次のとおりです:
Object.defineProperty は配列添字の変更を監視できないため、配列添字を介して要素が追加され、リアルタイムで応答
できませんObject.defineProperty はオブジェクトのプロパティのみをハイジャックできるため、各オブジェクトが必要です
属性がトラバースされます。属性値がオブジェクトの場合は、深さのトラバースも必要です。プロキシはオブジェクト全体をハイジャックして、新しいオブジェクトを返すことができます。

プロキシはオブジェクトをプロキシするだけでなく、配列をプロキシすることもできます。動的に追加された属性をプロキシすることもできます。プロキシには 13 ものインターセプト メソッドがあります。新しい標準として、プロキシはブラウザ メーカーによる継続的なパフォーマンスの最適化の対象になります。プロキシはオブジェクトの最初のレイヤーのみをプロキシします。では、Vue3 はこの問題にどのように対処しますか? Reflect.get の現在の戻り値が Object であるかどうかを確認し、Object である場合は、reactive メソッドをプロキシとして使用することで、詳細な観察を実現します。配列を監視する場合、get/set が複数回トリガーされる可能性があります。複数回トリガーされないようにするにはどうすればよいでしょうか? キーが現在のプロキシ オブジェクト ターゲット自体の属性であるか、古い値と新しい値が等しいかどうかを判断でき、上記 2 つの条件のいずれかが満たされた場合にのみ、トリガーを実行できます。
ここに画像の説明を挿入します

ここに画像の説明を挿入します
ここに画像の説明を挿入します

38.Vue 3 でグローバル変数を設定するにはどうすればよいですか?

方法 1: config.globalProperties vue2.x は、フォームを
使用してグローバルにマウントし、グローバルにマウントされた変数またはメソッドを取得します。Vue.prototype.$xxxx=xxx this.$xxx

Vue 3 では、これは config.globalProperties に相当します。これらのプロパティは、インスタンス化されたコンポーネントの一部としてアプリケーションにコピーされます。

// 之前 (Vue 2.x)
Vue.prototype.$http = () => {}

// 之后 (Vue 3.x)
const app = createApp({})
app.config.globalProperties.$http = () => {}

方法 2 Provide / Inject
vue3 の新しい Provide/Inject 関数は、マルチレイヤー コンポーネントを貫通し、親コンポーネントから子コンポーネントにデータを転送できます。

ルート コンポーネントのプロバイダーにグローバル変数を配置すると、すべてのコンポーネントがこの変数を使用できるようになります。

変数を応答させる必要がある場合は、変数を指定するときに ref または reactive を使用して変数をラップする必要があります。

39.VueのCSSスコープの原理は何ですか?

40.Vueテンプレートをコンパイルするにはどうすればよいですか?

この問題の核心は、テンプレートをレンダリング関数に変換する方法です。

テンプレートモジュールをAST文法書に変換 - parserHTML

静的構文をマークします (一部のノードは変更されません)

コードを再生成します - codeGen、with 構文を使用して文字列をラップします

41.Vueの差分アルゴリズム?

簡単に言うと、diff アルゴリズムには次のプロセスがあります:
ピアを比較し、次に子ノードを比較します。

  • まず、一方のパーティに子ノードがあるかどうかを確認します。
  • 一方のパーティに子ノードがない場合 (新しい子に子ノードがない場合、古い子ノードは削除されます) の比較
  • 両方に子ノード (コア diff) がある場合、子ノードを再帰的に比較します
  • 2 つのツリー間の通常の Diff の時間計算量は O(n^3) ですが、実際の状況では DOM をレベル間で移動することはほとんどないため、Vue は Diff を O(n^3) -> O (n) に最適化しました。
  • 古い子と新しい子が複数の子ノードである場合にのみ、コア Diff アルゴリズムを同じレベルの比較に使用する必要があります。

Vue2 のコア Diff アルゴリズムは両端比較アルゴリズムを採用しており、同時に古い子と新しい子の両端から比較を開始し、キー値を使用して再利用可能なノードを見つけ、関連する操作を実行します。同じ状況下で React の Diff アルゴリズムと比較すると、モバイル ノードの数を減らし、不必要なパフォーマンスの損失を減らすことができ、よりエレガントです。


Vue3.x は、VNode の作成時に ivi アルゴリズムと inferno アルゴリズムを利用して VNode のタイプを決定し、マウント/パッチ プロセス中にビット操作を使用して VNode のタイプを決定します。これに基づいて、コア Diff アルゴリズムと連携しますVue2.xと比べて改善されました。このアルゴリズムでは、動的プログラミングの考え方も使用して、最長の再帰サブシーケンスを解決します。

42. Vue プロジェクトをデプロイするにはどうすればよいですか? サーバーを展開した後に 404 を更新するという問題が発生したことがありますか?

1. 導入方法

フロントエンド・バックエンド分離開発モードでは、フロントエンドとバックエンドが独立してデプロイされ、フロントエンドはターゲットサーバーのWebコンテナが指定する静的ディレクトリに最終構築物をアップロードするだけで済みます。

vue プロジェクトがビルドされた後、一連の静的ファイルが生成されることがわかっています。

従来の展開では、このディレクトリをターゲット サーバーにアップロードするだけで済みます。

// scp アップロード ユーザーはホストのログイン ユーザー、ホストはホストの外部ネットワーク IP、xx は Web コンテナーの静的リソース パスです
scp dist.zip user@host:/xx/xx/xx

nginx を例として、Web コンテナを実行します。

server {
  listen  80;
  server_name  www.xxx.com;

  location / {
    index  /data/dist/index.html;
  }
}
配置完成记得重启nginx

// 检查配置是否正确
nginx -t 

// 平滑重启
nginx -s reload
操作完后就可以在浏览器输入域名进行访问了

もちろん、上記では最も単純かつ直接的な展開方法についてのみ言及しています。

自動化、ミラーリング、コンテナー、およびパイプラインのデプロイメントの本質は、この一連のロジックを抽象化して分離し、プログラムを使用して反復的な作業を置き換えることです。この記事では詳しく説明しません。

2. 404問題

これは古典的な質問で、多くの学生が遭遇したことがあると思いますが、本当の理由を知っていますか?

まずシーンを復元しましょう。

vue プロジェクトは、ローカルにある場合は正常に実行されますが、サーバーにデプロイされてページが更新されると、404 エラーが発生します。まず見つけてください。HTTP 404 エラーは、リンクが指すリソースが存在しないことを意味します

問題は、なぜそれが存在しないのかということです。そして、なぜこの問題は履歴モードでのみ発生するのでしょうか?

履歴モードで問題が発生するのはなぜですか?
Vue はシングルページ アプリケーション (シングルページ アプリケーション) です。

SPA は、ネットワーク アプリケーションまたは Web サイトのモデルです。すべてのユーザー インタラクションは、現在のページを動的に書き換えることによって行われます。前に見たように、適用するページの数に関係なく、この構造は 1 つのindex.html のみを生成します。

さて、戻って nginx 設定を見てみましょう

server {
  listen  80;
  server_name  www.xxx.com;

  location / {
    index  /data/dist/index.html;
  }
}

nginxの設定によれば、アドレスバーにwww.xxx.comと入力すると、distディレクトリ内のindex.htmlファイルが開き、ジャンプルートでwww.xxx.com/loginにジャンプします。

ここで重要なのは、website.com/login ページで更新操作を実行すると、nginx の場所に関連する設定がないため、404 が発生するということです。

ルーターのハッシュ モードで問題がないのはなぜですか
? ハッシュ モードは、website.com/#/login のように記号 # で表され、ハッシュ値は #/login であることは誰もが知っています。

その特徴は、ハッシュは URL に表示されますが、HTTP リクエストには含まれず、サーバーにまったく影響を与えないため、ハッシュを変更してもページがリロードされないことです。

ハッシュ モードでは、ハッシュ記号の前のコンテンツのみがリクエストに含まれます。たとえば、website.com/#/login のみがリクエストに含まれます。したがって、サーバーの場合、場所が設定されていない場合、404 エラーは返されません

3. 解決策

これを見れば、ほとんどの学生は問題の解決方法を考えることができると思います。

問題の本質は、ルートが JS を介してビューの切り替えを実行することです。

サブルートに入ってページを更新すると、Web コンテナに対応するページがない場合、404 が表示されます。

したがって、必要な設定は、任意のページをindex.htmlにリダイレクトし、処理のためにフロントエンドにルーティングを任せるだけです。

nginx 設定ファイル .conf を変更し、try_files $uri $uri/ /index.html を追加します。

server {
  listen  80;
  server_name  www.xxx.com;

  location / {
    index  /data/dist/index.html;
    try_files $uri $uri/ /index.html;
  }
}
修改完配置文件后记得配置的更新

nginx -s reload

これを行うと、すべてのパスに対して Index.html ファイルが返されるため、サーバーは 404 エラー ページを返さなくなります。

これを回避するには、Vue アプリケーションですべてのルーティング状況をカバーしてから、404 ページを与える必要があります。

const router = new VueRouter({
  mode: 'history',
  routes: [
    { path: '*', component: NotFoundComponent }
  ]
})

バックエンド構成ソリューション: Apache、nodejs などについては、考え方は同じなので、ここでは詳しく説明しません。

43.v-if は v-for と併用することは推奨されませんか?

v-for が最初に解析され、v-if は解析中に解析されるため、同じタグ内で v-for と v-if を使用しないでください。これらを同時に使用する必要がある場合は、計算された属性として記述することを検討できます。

同じ要素に対して v-if と v-for を同時に使用しないでください。パフォーマンスが無駄になります (各レンダリングは最初にループし、次に条件判断を実行します)。

この状況を回避するには、テンプレートを外層にネストし(ページレンダリングでは dom ノードは生成されません)、この層で v-if 判定を実行し、内部で v-for ループを実行します。

44.Vueコンポーネント間の通信方法は何ですか?

Vue コンポーネント間の通信には、親子コンポーネント通信、世代間コンポーネント通信、兄弟コンポーネント通信の 3 種類の通信のみを指します。以下では、それぞれの通信方法を個別に紹介し、どの種類のコンポーネント間通信に適用できるかを説明します。に。

(1) props / $emit は親子コンポーネントの通信に適しています。
この方法は Vue コンポーネントの基本であり、ほとんどの学生が知っていると思いますので、ここでは例を挙げて紹介しません。

(2) ref と $parent / $children は親子コンポーネント通信に適しています
ref: 通常の DOM 要素で使用される場合、参照は DOM 要素を指します; 子コンポーネントで使用される場合、参照はコンポーネント インスタンスを指します
$parent / $children: 親/子インスタンスにアクセスします

(3) EventBus ($emit / $on) このメソッドは、親子、世代間、兄弟コンポーネントの通信に適しており、
空の Vue インスタンスを中央のイベント バス (イベント センター) として使用し、それを使用してイベントをトリガーします。また、イベントを監視して、親子コンポーネント、世代スキップコンポーネント、兄弟コンポーネントなどのコンポーネント間の通信を実現します。

(4)attrs / attrs/tt rs / listens は、世代間のコンポーネント通信に適しています。これには、
$attrs親スコープ内の prop によって認識されない (および取得されない) プロパティ バインディング (クラスとスタイルを除く) が含まれます。 v-bind="$attrs"コンポーネントが props を宣言していない場合、すべての親スコープ バインディング (クラスとスタイルを除く) がここに含まれ、内部コンポーネントに渡すことができます通常は、inheritAttrs オプションと一緒に使用されます。
$listeners: 親スコープに v-on イベント リスナーが含まれます (.native 修飾子なし)。v-on="$listeners"経由で内部コンポーネントに渡すことができます。

(5) Provide/inject は世代間のコンポーネント通信に適しており、
祖先コンポーネントでは Provider で変数を提供し、子孫コンポーネントでは Inject で変数を注入します。Provide/Inject API は主にクロスレベルコンポーネント間の通信問題を解決しますが、その使用シナリオは主にサブコンポーネントが上位コンポーネントのステータスを取得するためのものであり、クロスレベルコンポーネント間でアクティブプロビジョニングと依存関係注入の関係が確立されます。 。

(6) Vuex は、親子、世代間、兄弟間のコンポーネント通信に適しています
Vuex は、Vue.js アプリケーション用に特別に開発された状態管理モデルです。すべての Vuex アプリケーションの中核はストアです。「ストア」は基本的に、アプリケーション内のほとんどの状態を含むコンテナーです。
Vuex の状態ストレージはリアクティブです。Vue コンポーネントがストアから状態を読み取るときに、ストア内の状態が変化すると、それに応じて対応するコンポーネントが効率的に更新されます。
ストア内の状態を変更する唯一の方法は、ミューテーションを明示的にコミットすることです。これにより、あらゆる状態変化を簡単に追跡できるようになります。

45.Vue のツリー振動機能とは何ですか? 例を挙げる?

1.とは

ツリーシェイキングとは、冗長なコードを排除することでプロジェクトのパッケージング量を最適化する技術で、専門用語ではデッドコード排除と呼ばれます。

簡単に言うと、コードの実行結果は変えずに、無駄なコードを削除することです。

パッケージングコードをケーキ作りに例えると、従来の方法は、(殻付きの) 卵をすべて入れて混ぜ、オーブンに入れ、最後に (無駄な) 卵の殻をすべて選択して取り除くことです。

ツリーシェイキングでは、最初に有用な卵白と卵黄(輸入品)をミックスに入れ、最後に直接ケーキを作ります。

言い換えれば、ツリーシェイクは実際に使用されているコードを見つけ出すことです

Vue2 では、どのような機能を使用しても、最終的には製品コードに組み込まれます。主な理由は、Vue インスタンスがプロジェクト内のシングルトンであり、バンドラーがコード内でオブジェクトのどのプロパティが使用されているかを検出できないことです。

import Vue from 'vue'

Vue.nextTick(() => {
    
    })

Vue3 ソース コードには、グローバル API をチャンクに分割するためのツリー シェーキング機能が導入されています。一部の機能を使用しない場合、それらは基本パッケージに含まれません。

import {
    
     nextTick, observable } from 'vue'

nextTick(() => {
    
    })

2.やり方

ツリー シェイキングは ES6 テンプレート構文 (インポートとエクスポート) に基づいており、主に ES6 モジュールの静的コンパイルの考え方に依存して、コンパイル時にモジュールと入出力変数の依存関係を決定します。

木の揺れは次の 2 つのことを行うだけです。

コンパイル段階では、ES6 モジュールを使用して、どのモジュールがロードされているかを確認し、
どのモジュールと変数が使用または参照されていないかを判断し、対応するコードを削除します。

3. 機能

ツリー シェイキングを通じて、Vue3 がもたらす利点は次のとおりです。

  • プログラムのサイズを小さくする(小さくする)
  • プログラムの実行時間を短縮(高速化)
  • 将来的にはプログラム アーキテクチャの最適化を促進します (よりフレンドリーに)

46.$routeと$routerの違いは何ですか?

Vue.js では、$route と $router はどちらもルーティング関連のオブジェクトですが、次のような違いがあります。

  1. $route:$route 現在の URL パス、クエリ パラメータ、パス パラメータ、その他の情報を含む、現在のルーティング情報のオブジェクトです。$route オブジェクトは読み取り専用であり、その属性値は直接変更できませんが、ルーティング ジャンプを通じて更新する必要があります。

  2. $router:$routerこれは Vue Router のインスタンス オブジェクトであり、プッシュ、置換、ゴー、フォワードなどのメソッドなど、ナビゲーション制御およびルーティング操作のための多くの API が含まれています。$router これを使用して URL を動的に変更し、更新のないページ間のジャンプを実現できます。

$routeその$routerため$route主に現在の経路情報を取得するために使用されます$router が、指定された経路へのジャンプや順方向、逆方向などのルーティング操作を行うために使用されます。一般的に、$routeと は$router密接な関係にあり、一緒に使用されることがよくあります。

47.V3とV2の違いは何ですか?

主な違いのいくつかを以下にまとめます。

  • リアクティブ システム: Vue 3 では、新しいリアクティブ システムである Comboposition API が導入されています。Comboposition API は、コンポーネントの状態とロジックを管理するためのより柔軟で強力な方法を提供し、コードの編成と再利用をより便利にします。Comboposition API はオブジェクトの代わりに関数を使用するため、ツリー シェーキングの最適化が向上し、パッケージ サイズが削減されます。

  • パッケージ サイズの縮小: Vue 3 は、より優れた Tree Shaking とより効率的なランタイム コード生成により、Vue 2 よりもパッケージ サイズが小さくなっています。Vue 3 の応答システムも、パフォーマンスを向上させるために最適化されています。

  • パフォーマンスの向上: Vue 3 は、新しいコンパイラーのおかげで、より高速で効率的なレンダリング メカニズムを備えています。仮想 DOM の微分アルゴリズムが最適化され、不要な更新が削減され、レンダリング パフォーマンスが向上しました。

  • スコープ付きスロットの置き換え: Vue 3 では、スコープ付きスロットの概念がより直感的で簡略化された構文に置き換えられ、コンポーネント構成でのスロットの定義と使用が容易になります。

  • Teleport コンポーネントの導入: Vue 3 では Teleport コンポーネントが導入されました。これは、DOM ツリー内のさまざまな場所でコンテンツをレンダリングでき、モーダル ボックス、ツールヒント、その他のオーバーレイ効果の作成に使用されます。

  • Fragments : Vue 3 では、追加のラッピング要素を追加せずに複数の要素をグループ化できる Fragment と呼ばれる組み込みコンポーネントが導入されました。

  • TypeScript サポートの向上: Vue 3 では、デフォルトで TypeScript サポートが強化され、型推論が強化され、TypeScript ツールとの統合が強化されています。

  • 簡素化された API : Vue 3 では、多くの API が簡素化および最適化され、フレームワークの学習と使用が容易になりました。新しい API により、一貫性が向上し、JavaScript 標準との整合性が向上します。

Vue 3 ではこれらの変更が導入されていますが、Vue 2 API との下位互換性が維持されているため、既存の Vue 2 プロジェクトを段階的にアップグレードできます。Vue 3 は、ほとんどの Vue 2 コードと互換性のある移行済みビルドを提供するため、開発者にとって移行がよりスムーズになります。

全体として、Vue 3 はパフォーマンス、パッケージ サイズ、開発者のエクスペリエンスを大幅に向上させると同時に、コンポーネントの状態とロジックを管理するためのより強力なツールとして Comboposition API を導入しました。

48.命令型開発と比較した Vue のレスポンシブ開発の利点は何ですか?

Vue のレスポンシブ開発には、命令型開発と比較して次の利点があります。

  1. 簡略化されたコード: Vue では、データとテンプレートをバインドすることによってビューの更新が自動化されるため、手動で DOM を操作するような面倒でエラーが発生しやすい操作が回避されます。その結果、定型コードの作成とデバッグ コードの作成に必要な時間を大幅に短縮できます。

  2. 保守性の向上: Vue を使用したレスポンシブ開発は、アプリケーションの状態をより便利に管理し、状態の変化を均一に処理するのに役立ちます。これにより、コードの可読性と保守性が向上するだけでなく、単体テストと統合テストも容易になります。

  3. ユーザー エクスペリエンスの向上: Vue のレスポンシブ開発により、部分更新や非同期読み込みなどの機能を実装できるため、ユーザー エクスペリエンスが向上します。たとえば、項目がリストに追加またはリストから削除された場合、リスト全体を再レンダリングするのではなく、対応する項目のみを更新する必要があります。別の例として、大量の画像を読み込む場合、非同期読み込みと遅延読み込みを使用して、ページの読み込み速度とユーザー エクスペリエンスを向上させることができます。

  4. 複雑なコンポーネント設計のサポート: Vue のレスポンシブ開発はコンポーネントベースの設計をサポートしており、大規模なアプリケーションを複数の小さな再利用可能なコンポーネントに簡単に分割できます。これらのコンポーネントは、必要に応じてネストしたり組み合わせたりして、より複雑で機能豊富な UI インターフェイスを形成できます。また、各コンポーネントは独立した状態とライフ サイクルを持ちます。

つまり、Vue のレスポンシブ開発は、フロントエンド開発をより効率的、便利、柔軟に行うのに役立ち、それによってより良いユーザー エクスペリエンスとより高いコード品質を提供します。

49.Vueでよく使われる修飾子は何ですか? どのようなアプリケーション シナリオに使用されますか?

1. 修飾子とは何ですか?

プログラミングの世界では、修飾子は型および型メンバーの宣言を修飾するために使用される記号です。

Vue では、修飾子が DOM イベントの多くの詳細を処理するため、これらの面倒な処理に多くの時間を費やす必要がなくなり、より多くのエネルギーをプログラムのロジック処理に集中できるようになります。

Vue のモディファイアは次の 5 種類に分類されます。

表单修饰符
事件修饰符
鼠标按键修饰符
键值修饰符
v-bind修饰符

2. 修飾子の役割


最も一般的に使用されるフォーム修飾子は、フォームに入力するときに入力タグであり、最も一般的に使用されるコマンドは v-model です。

フォームに関する修飾子は次のとおりです。

lazy
trim
number
lazy

情報を入力し、カーソルがラベルから離れると、値が value に割り当てられます。つまり、変更イベントの後に情報が同期されます。

  • 怠け者
<input type="text" v-model.lazy="value">
<p>{
    
    {
    
    value}}</p>
  • トリムは、
    ユーザーが入力した最初のスペース文字を自動的にフィルタリングしますが、中間のスペースはフィルタリングされません。
<input type="text" v-model.trim="value">
  • number は、
    ユーザーの入力値を数値型に自動的に変換しますが、値が parseFloat で解析できない場合は、元の値が返されます。
<input v-model.number="age" type="number">

イベント修飾子
イベント修飾子は、イベント キャプチャとターゲットを処理します。次の修飾子があります。

stop
prevent
self
once
capture
passive
native
  • stop は
    イベントのバブリングを防ぎます。これは、event.stopPropagation メソッドを呼び出すことと同じです。
<div @click="shout(2)">
  <button @click.stop="shout(1)">ok</button>
</div>
//只输出1
  • Prevent は
    、イベントのデフォルトの動作を防止します。これは、event.preventDefault メソッドを呼び出すのと同じです。
<form v-on:submit.prevent="onSubmit"></form>
  • self は、
    event.target が現在の要素自体である場合にのみハンドラー関数をトリガーします
<div v-on:click.self="doThat">...</div>

修飾子を使用する場合は順序が重要であり、対応するコードは同じ順序で生成されます。したがって、 v-on:click.prevent.self を使用するとすべてのクリックが防止されますが、 v-on:click.self.prevent は要素自体のクリックのみが防止されます。

  • Once
    がバインドされた後は、イベントは 1 回だけトリガーされ、2 回目はトリガーされません。
<button @click.once="shout(1)">ok</button>
  • Capture により、
    この要素を含む最上位レベルから下方向にイベントが発生します。
<div @click.capture="shout(1)">
    obj1
<div @click.capture="shout(2)">
    obj2
<div @click="shout(3)">
    obj3
<div @click="shout(4)">
    obj4
</div>
</div>
</div>
</div>
// 输出结构: 1 2 4 3 
  • パッシブ
    モバイル側では、要素のスクロール イベントをリッスンしているときに、onscroll イベントが常にトリガーされ、Web ページがスタックするため、この修飾子を使用すると、onscroll イベントに .lazy 修飾子を追加するのと同じになります。 。
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成  -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>

.prevent は無視され、ブラウザに警告が表示される可能性があるため、.passive と .prevent を一緒に使用しないでください。

パッシブは、イベントのデフォルトの動作をブロックしたくないことをブラウザーに伝えます。

  • ネイティブを
    使用すると、コンポーネントは組み込み HTML タグなどのルート要素のネイティブ イベントをリッスンできます。それ以外の場合、コンポーネントで v-on を使用するとカスタム イベントのみをリッスンします。
<my-component v-on:click.native="doSomething"></my-component>

.native 修飾子を使用して通常の HTML タグを操作すると、イベントが無効になります。

マウス ボタンの修飾子
マウス ボタンの修飾子は、次のように左クリック、右クリック、中クリックに対応します。

left 左键点击
right 右键点击
middle 中键点击
<button @click.left="shout(1)">ok</button>
<button @click.right="shout(1)">ok</button>
<button @click.middle="shout(1)">ok</button>

キーボード修飾子
キーボード修飾子は、次のようにキーボード イベント (onkeyup、onkeydown) を変更するために使用されます。

keyCode は数多くありますが、vue ではエイリアスが用意されており、次の 2 種類に分けられます。

通常のキー (enter、tab、delete、space、esc、up...)
システム修飾キー (ctrl、alt、meta、shift...)
// キーが keyCode の場合にのみトリガーされます

<input type="text" @keyup.keyCode="shout()">

次の方法で、一部のグローバル キーボード コード エイリアスをカスタマイズすることもできます。

Vue.config.keyCodes.f2 = 113

v-bind 修飾子
v-bind 修飾子は主にプロパティを操作するために使用され、次のように使用されます。

sync
prop
camel
sync

小道具に対して双方向のバインドを実行できます

//父组件
<comp :myMessage.sync="bar"></comp> 
//子组件
this.$emit('update:myMessage',params);
以上这种方法相当于以下的简写

//父亲组件
<comp :myMessage="bar" @update:myMessage="func"></comp>
func(e){
    
    
 this.bar = e;
}
//子组件js
func2(){
    
    
  this.$emit('update:myMessage',params);
}

同期を使用する場合は、次の 2 つの点に注意する必要があります。

同期を使用する場合、サブコンポーネントによって渡されるイベント名の形式は update:value である必要があり、value はサブコンポーネントの props で宣言された名前とまったく同じである必要があります。

.sync 修飾子を含む v-bind は式では使用できないことに注意してください。

v-bind.sync="{ title: doc.title }" などのリテラル オブジェクトに対して v-bind.sync を使用すると、正しく動作しません。

  • props は、
    データの公開を回避し、HTML 構造の汚染を防ぐためにカスタム タグ属性を設定します。
<input id="uid" title="title1" value="1" :index.prop="index">
  • Camel は、
    view-Box 属性名を viewBox に変換するなど、名前をキャメルケースに変更します。
<svg :viewBox="viewBox"></svg>

3. 応用シナリオ

各モディファイアの機能に応じて、次のようなモディファイアの適用シナリオを取得できます。

.stop:阻止事件冒泡
.native:绑定原生事件
.once:事件只执行一次
.self :将事件绑定在自身身上,相当于阻止事件冒泡
.prevent:阻止默认事件
.capture:用于事件捕获
.once:只触发一次
.keyCode:监听特定键盘按下
.right:右键

50.Vueの親コンポーネントと子コンポーネントのライフサイクルフック関数の実行順序は何ですか?

Vue の親コンポーネントと子コンポーネントのライフサイクルフック関数の実行シーケンスは、次の 4 つの部分に分類できます。

レンダリング処理をロードする

父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted

サブコンポーネントの更新プロセス

父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated

親コンポーネントの更新プロセス

父 beforeUpdate -> 父 updated

破壊プロセス

父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed

51. コンポーネント内のデータが関数なのはなぜですか?

コンポーネント内のデータは関数にしてからオブジェクトを返さなければならないのに、新しい Vue インスタンスではデータを直接オブジェクトにできるのはなぜですか?

// data
data() {
    
    
  return {
    
    
    message: "子组件",
    childName:this.name
  }
}

// new Vue
new Vue({
    
    
  el: '#app',
  router,
  template: '<App/>',
  components: {
    
    App}
})

コンポーネントは再利用のために使用され、JS内のオブジェクトは参照関係であるため、コンポーネント内のデータがオブジェクトの場合、スコープが分離されず、サブコンポーネント内のデータ属性値が相互に影響します。コンポーネントのデータ オプションが
関数の場合、各インスタンスは返されたオブジェクトの独立したコピーを維持でき、コンポーネント インスタンス間のデータ属性値は相互に影響を与えず、新しい Vue インスタンスは影響を受けません。再利用されるため、参照オブジェクトが存在しないという問題があります。

52.クラスとスタイルを動的にバインドするにはどうすればよいですか?

クラスは、オブジェクト構文および配列構文を通じて動的にバインドできます。
オブジェクト構文:

<div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>

data: {
    
    
  isActive: true,
  hasError: false
}

配列の構文:

<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>

data: {
    
    
  activeClass: 'active',
  errorClass: 'text-danger'
}

スタイルは、オブジェクト構文および配列構文を通じて動的にバインドすることもできます。
オブジェクト構文:

<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

data: {
    
    
  activeColor: 'red',
  fontSize: 30
}

配列の構文:

<div v-bind:style="[styleColor, styleSize]"></div>

data: {
    
    
  styleColor: {
    
    
     color: 'red'
   },
  styleSize:{
    
    
     fontSize:'23px'
  }
}

53.Vueの一方向データフローを理解するにはどうすればよいですか?

すべてのプロパティは、親プロパティと子プロパティの間で一方向の下向きバインディングを形成します。親プロパティからの更新は下向きに子コンポーネントに流れますが、その逆は起こりません。

これにより、子コンポーネントが親コンポーネントの状態を誤って変更して、アプリケーションのデータ フローが理解しにくくなるのを防ぐことができます。

さらに、親コンポーネントが更新されるたびに、子コンポーネント内のすべてのプロパティが最新の値に更新されます。
これは、子コンポーネント内の props を変更すべきではないことを意味します。これを行うと、Vue はブラウザーのコンソールに警告を発行します。

子コンポーネントが変更したい場合、カスタム イベントは $emit を通じてのみ送出され、親コンポーネントがそれを受信した後、親コンポーネントによって変更されます。

プロップを変更しようとする場合、一般的な状況が 2 つあります。

  • この prop は初期値を渡すために使用され、サブコンポーネントはそれをローカル prop データとして使用したいと考えます。この場合、ローカル データ プロパティを定義し、このプロパティを初期値として使用することをお勧めします。
props: ['initialCounter'],
data: function () {
    
    
  return {
    
    
    counter: this.initialCounter
  }
}
  • このプロパティは生の値として渡されるため、変換する必要があります。この場合、このプロパティの値を使用して計算されたプロパティを定義することをお勧めします。
props: ['size'],
computed: {
    
    
  normalizedSize: function () {
    
    
    return this.size.trim().toLowerCase()
  }
}

54. 配列項目に値を直接割り当てた場合、Vue はその変更を検出できますか?

JavaScript の制限により、Vue は次の配列の変更を検出できません:
インデックスを使用して配列項目を直接設定した場合 (例: vm.items[indexOfItem] = newValue)

配列の長さを変更する場合、例: vm.items.length = newLength

最初の問題を解決するために、Vue は次のメソッドを提供します。

// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// vm.$set,Vue.set的一个别名
vm.$set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

2 番目の問題を解決するために、Vue は次の操作メソッドを提供します。

// Array.prototype.splice
vm.items.splice(newLength)

55. 非同期リクエストはどのライフサイクルで呼び出されますか?

これら 3 つのフック関数ではデータが作成され、サーバーから返されたデータを割り当てることができるため、作成されたフック関数、beforeMount、およびマウントされたフック関数で呼び出すことができます。ただし、作成したフック関数で非同期リクエストを呼び出すことをお勧めします。作成したフック関数で非同期リクエストを呼び出すと、
サーバー データの取得が速くなり、ページの読み込み時間が短縮されるという利点があるためです。

ssr は beforeMount およびマウントされたフック関数をサポートしていないため、それらを created に配置すると一貫性が保たれます。

56. DOM はどの段階でアクセスして操作できますか?

マウントされたフック関数が呼び出される前に、Vue はコンパイルされたテンプレートをページにマウントしているため、マウントされた状態で DOM にアクセスして操作できます。
vue の具体的なライフサイクル図は以下のとおりで、ライフサイクル全体の各段階の動作を理解すれば、面接でのライフサイクル関連の質問に困ることはなくなります。
ここに画像の説明を挿入します

57. 親コンポーネントは子コンポーネントのライフサイクルを監視できますか?

たとえば、親コンポーネントParentと子コンポーネントChildがある場合、親コンポーネントは子コンポーネントがマウントされていることを検出すると、論理的な処理を行います。これは次のように記述することで実現できます。

// Parent.vue
<Child @mounted="doSomething"/>

// Child.vue
mounted() {
    
    
  this.$emit("mounted");
}

上記では、$emit を介して親コンポーネントのイベントを手動でトリガーする必要があります。より簡単な方法は、以下に示すように、親コンポーネントが子コンポーネントを参照するときに @hook を介してリッスンすることです。

//  Parent.vue
<Child @hook:mounted="doSomething" ></Child>

doSomething() {
    
    
   console.log('父组件监听到 mounted 钩子函数 ...');
},

//  Child.vue
mounted(){
    
    
   console.log('子组件触发 mounted 钩子函数 ...');
},    

// 以上输出顺序为:
// 子组件触发 mounted 钩子函数 ...
// 父组件监听到 mounted 钩子函数 ...

もちろん、 @hook メソッドはマウントされたイベントだけでなく、作成、更新などの他のライフサイクル イベントも監視できます。

58. v-modelの原理は何ですか?

vue プロジェクトでは、主に v-model ディレクティブを使用して、フォーム入力、テキストエリア、選択、その他の要素に双方向のデータ バインディングを作成します。v-model は本質的に単なる糖衣構文であることがわかっています。v-model は内部的に次の目的で使用されます。異なる入力要素 異なる属性と異なるイベントをスローする:
text 要素と textarea 要素は value 属性と input イベントを使用します。

チェックボックスとラジオは、checked 属性と変更イベントを使用します。

選択フィールドにはプロパティとして値があり、イベントとして変更が含まれます。

入力フォーム要素を例に挙げます。

<input v-model='something'>

相当于

<input v-bind:value="something" v-on:input="something = $event.target.value">

カスタム コンポーネント内の場合、v-model は、次に示すように、デフォルトで value という名前のプロップと input という名前のイベントを使用します。

父组件:
<ModelChild v-model="message"></ModelChild>

子组件:
<div>{
    
    {
    
    value}}</div>

props:{
    
    
    value: String
},
methods: {
    
    
  test1(){
    
    
     this.$emit('input', '小红')
  },
},

59.vue-router にはルーティング モードがいくつありますか?

vue-router にはハッシュ、ヒストリー、アブストラクトの 3 つのルーティング モードがあり、対応するソース コードは次のとおりです。

switch (mode) {
    
    
  case 'history':
    this.history = new HTML5History(this, options.base)
    break
  case 'hash':
    this.history = new HashHistory(this, options.base, this.fallback)
    break
  case 'abstract':
    this.history = new AbstractHistory(this, options.base)
    break
  default:
    if (process.env.NODE_ENV !== 'production') {
    
    
      assert(false, `invalid mode: ${
      
      mode}`)
    }
}

このうち、3 つのルーティング モードの説明は次のとおりです。

  • hash: ルーティングに URL ハッシュ値を使用します。HTML5 History API をサポートしていないブラウザを含む、すべてのブラウザをサポートします。
  • 履歴: HTML5 履歴 API とサーバー構成に依存します。詳細については、HTML5 履歴モードを参照してください。
  • 要約: Node.js サーバー側など、すべての JavaScript ランタイム環境をサポートします。ブラウザ API がないことが判明した場合、ルーティングは自動的にこのモードに強制されます。

60.MVVMとは何ですか?

Model–View–ViewModel (MVVM) は、Microsoft WPF と Silverlight のアーキテクトである Ken Cooper と Ted Peters によって開発されたソフトウェア アーキテクチャ設計パターンであり、ユーザー インターフェイスを簡素化するイベント駆動型プログラミング手法です。

MVVM は、古典的なモデル – ビュー – コントローラー (MVC) パターンに由来しています。MVVM の登場により、フロントエンド開発とバックエンド ビジネス ロジックの分離が促進され、フロントエンド開発の効率が大幅に向上しました。MVVM の中核となるのは、 ViewModel レイヤーは、転送ステーション (値コンバーター) のようなもので、データの管理と使用を容易にするためにモデル内のデータ オブジェクトを変換する役割を果たします。このレイヤーは、ビュー レイヤーとの双方向のデータ バインディングを上向きに実行し、モデル層はインターフェースを介して下向きのリクエストを行い、上下をリンクする役割を果たします。

以下に示すように:
ここに画像の説明を挿入します

(1) ビュー層
ビューはユーザーインターフェースであるビュー層です。フロントエンドは主にHTMLとCSSで構築されています。

(2) モデル層
モデルとはデータモデルのことであり、一般にバックエンドで行われる各種ビジネスロジックの処理やデータ操作を指し、フロントエンドの場合はバックエンドが提供するAPIインターフェースを指します。

(3) ViewModel 層
ViewModel は、フロントエンド開発者によって生成および保守されるビュー データ層です。この層では、フロントエンド開発者がバックエンドから取得したモデル データを変換し、二次カプセル化を実行して、ビュー層の期待を満たすビュー データ モデルを生成します。

ViewModel によってカプセル化されたデータ モデルにはビューの状態と動作が含まれますが、モデル レイヤーのデータ モデルには、ページのこの部分に表示される内容やページが表示されたときに何が起こるかなどの状態のみが含まれることに注意してください。ブロックに何が起こるか、このブロックがスクロールされたときに何が起こるかはすべてビューの動作 (インタラクション) に属し、ビューの状態と動作は ViewModel にカプセル化されます。このようなカプセル化により、ViewModel は View 層を完全に記述することができます。

MVVM フレームワークは双方向バインディングを実装しているため、ViewModel のコンテンツはリアルタイムで View レイヤーに表示されます。フロントエンド開発者は、DOM を操作して非効率的かつ面倒なビューを更新する必要がなくなりました。MVVM フレームワークには、最も汚くて最も面倒な部分はすでに完了しているため、開発者は ViewModel を処理して保守するだけで済み、更新されたデータ ビューもそれに応じて自動的に更新されます。

この方法では、ビュー レイヤーには、モデル レイヤーのデータではなく、ビューモデルのデータが表示されます。ビューモデルは、モデル レイヤーとの対話を担当します。これにより、ビュー レイヤーとモデル レイヤーが完全に分離されます。この分離は非常に重要です。これは、フロントエンドとバックエンドであり、分離計画の実行の重要な部分です。

以下では、Vue の例を使用して MVVM の具体的な実装を説明します。Vue 開発経験のある学生であれば、一目で理解できるはずです。
(1) ビュー層

<div id="app">
    <p>{
    
    {
    
    message}}</p>
    <button v-on:click="showMessage()">Click me</button>
</div>

(2) ViewModel層

var app = new Vue({
    
    
    el: '#app',
    data: {
    
      // 用于描述视图状态
        message: 'Hello Vue!', 
    },
    methods: {
    
      // 用于描述视图行为
        showMessage(){
    
    
            let vm = this;
            alert(vm.message);
        }
    },
    created(){
    
    
        let vm = this;
        // Ajax 获取 Model 层的数据
        ajax({
    
    
            url: '/your/server/data/api',
            success(res){
    
    
                vm.message = res;
            }
        });
    }
})

(3) モデル層

{
    
    
    "url": "/your/server/data/api",
    "res": {
    
    
        "success": true,
        "name": "IoveC",
        "domain": "www.cnblogs.com"
    }
}

61.Vue フレームワークはオブジェクトと配列の監視をどのように実装しますか?

Vue2.x で配列の変更を検出する方法は、配列の一般的なメソッドを書き換えることです。Vue は、データ内の配列のプロトタイプ チェーンを書き換えて、独自に定義された配列プロトタイプ メソッドを指します。このようにして、配列 API が呼び出されたときに依存関係の更新を通知できます。配列に参照型が含まれている場合、配列内の参照型は監視のために再度再帰的に走査されます。これにより、アレイの変更を監視できるようになります。

プロセス:

  1. 受信データを初期化し、initData を実行します。
  2. 新しいオブザーバーを使用してデータを観察する
  3. プロトタイプをオーバーライドするポイント配列プロトタイプ メソッド
  4. 配列内の参照型を詳しく見る

配列への変更を検出できない状況は 2 つあります。

  1. インデックスを使用して配列項目を直接設定する場合 (例: vm.items[indexOfItem] = newValue)
  2. 配列の長さを変更する場合、たとえば vm.items.length = newLength

ただし、両方のシナリオに対応するソリューションがあります。インデックスを使用して配列項目を設定する代わりに
// このメソッドを使用してビューを更新します

// vm.$set,Vue.set的一个别名
vm.$set(vm.items, indexOfItem, newValue)

62. ProxyとObject.definePropertyの長所と短所の比較

プロキシの利点は次のとおりです。

  • プロキシはプロパティではなくオブジェクトを直接監視できます。
  • プロキシはアレイ内の変更を直接監視できます。
  • プロキシには、apply、ownKeys、deleteProperty、has などに限定されない、13 ものインターセプト メソッドがありますが、Object.defineProperty にはありません。
  • プロキシは新しいオブジェクトを返します。私たちは目的を達成するために新しいオブジェクトを操作することしかできませんが、Object.defineProperty はオブジェクトのプロパティを走査して直接変更することしかできません。
  • 新しい標準として、プロキシはブラウザ メーカーによる継続的なパフォーマンスの最適化の対象になります。これは、新しい標準の伝説的なパフォーマンス ボーナスです。

Object.defineProperty の利点は次のとおりです。

  • 互換性が高く、IE9 をサポートしていますが、Proxy にはブラウザ互換性の問題があり、ポリフィルで滑らかにすることができないため、Vue の作者は、Proxy で書き換えるには次のメジャー バージョン (3.0) まで待つ必要があると述べています。

63. Vue は、オブジェクトが新しい属性に応答できないという問題を解決するために vm.$set() をどのように使用しますか?

最新の JavaScript の制限により、Vue はオブジェクト プロパティの追加または削除を検出できません。
Vue はインスタンスの初期化時にプロパティのゲッター/セッター変換を実行するため、Vue がプロパティをリアクティブに変換するには、プロパティがデータ オブジェクトに存在する必要があります。
しかし、Vue にはオブジェクトに応答性の高いプロパティを追加するための Vue.set (object, propertyName, value) / vm.$set (object, propertyName, value) が用意されています。

対応する Vue ソース コードを確認してみましょう。

export function set (target: Array<any> | Object, key: any, val: any): any {
    
    
  // target 为数组
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    
    
    // 修改数组的长度, 避免索引>数组长度导致splcie()执行有误
    target.length = Math.max(target.length, key)
    // 利用数组的splice变异方法触发响应式
    target.splice(key, 1, val)
    return val
  }
  // key 已经存在,直接修改属性值
  if (key in target && !(key in Object.prototype)) {
    
    
    target[key] = val
    return val
  }
  const ob = (target: any).__ob__
  // target 本身就不是响应式数据, 直接赋值
  if (!ob) {
    
    
    target[key] = val
    return val
  }
  // 对属性进行响应式处理
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val
}

上記のソース コードを読むと、vm.$set の実装原則が次のとおりであることがわかります。

  • ターゲットが配列の場合は、配列の splice メソッドを直接使用して、対応する式をトリガーします。
  • ターゲットがオブジェクトの場合、まず属性が存在するかどうか、およびオブジェクトがリアクティブであるかどうかを判断し、最後に属性に対して応答処理を実行する場合は、defineReactive メソッドを呼び出して応答処理を実行します (defineReactive メソッドはVue がオブジェクトを初期化するとき、プロパティは Object.defineProperty によって呼び出されるメソッドを使用して動的にゲッター関数とセッター関数を追加します)。

64 カスタム命令? 応用シナリオ?

Vue では、カスタム ディレクティブは Vue のテンプレート構文を拡張するためのメカニズムです。カスタム ディレクティブを使用すると、DOM 要素にカスタム動作を追加し、要素の挿入、更新、削除時に対応する操作を実行できます。

カスタム ディレクティブは、ディレクティブ名とディレクティブ オプション オブジェクトの 2 つのパラメーターを受け取る Vue.directive 関数によって定義されます。ディレクティブ オプション オブジェクトには、ディレクティブの動作を定義する一連のフック関数が含まれています。

以下は、カスタム命令の一般的なアプリケーション シナリオの一部です。

  • DOM の操作: カスタム命令を使用して、要素のスタイル、属性、イベント バインディングなどの変更など、DOM 要素を直接操作できます。ディレクティブのフック関数を通じて DOM 要素にアクセスして操作できます

  • フォーム検証: カスタム ディレクティブを作成して、フォーム検証ロジックを実装できます。カスタム命令を通じて、入力ボックスの値の変化を監視し、カスタム検証ルールに基づいて検証を実行して、リアルタイムのフィードバックを提供できます。

  • 権限制御: ユーザー権限に基づいて特定の要素を非表示にしたり無効にしたりするなど、権限制御シナリオでカスタム命令を使用できます。カスタム命令のユーザー権限に基づいて条件判定を行い、要素の表示や動作を変更できます。

  • サードパーティ ライブラリの統合: Vue でサードパーティ ライブラリまたはプラグインを使用する必要がある場合、統合用のカスタム命令を使用できます。サードパーティのライブラリを初期化および構成し、適切なタイミングでライブラリのメソッドを呼び出すカスタム ディレクティブを作成できます。

  • アニメーションとトランジション効果: カスタム ディレクティブを Vue のトランジション システムで使用して、カスタム アニメーションとトランジション効果を実装できます。カスタム ディレクティブでトランジション フック関数をリッスンし、必要に応じて要素のスタイルまたはクラス名を操作して、トランジション効果を実現できます。

これらは一般的なアプリケーション シナリオの一部にすぎませんが、実際、カスタム命令には非常に幅広いアプリケーションがあり、特定のニーズに応じて柔軟に使用できます。カスタム命令を通じて、Vue の機能を拡張し、より複雑で柔軟なインタラクティブな動作を実現できます。

おすすめ

転載: blog.csdn.net/2201_75499330/article/details/131437792