ホームページ  >  記事  >  ウェブフロントエンド  >  Vue がインデックスを一意の識別子として使用できない理由の簡単な分析

Vue がインデックスを一意の識別子として使用できない理由の簡単な分析

青灯夜游
青灯夜游転載
2022-09-23 20:03:101529ブラウズ

vue一意の識別子としてインデックスを使用できないのはなぜですか? Vue が一意の識別子としてインデックスを使用できない理由については、次の記事で紹介していますので、ご参考になれば幸いです。

Vue がインデックスを一意の識別子として使用できない理由の簡単な分析

これには、ネイティブ JS の DOM 操作と仮想 DOM による最適化が含まれます。以下は 2 つの部分に分けて説明します。

1. 仮想 DOM

まず、dom ノードをネイティブに操作する方法を見てみましょう。ただし、ノードの変更によりブラウザは再配置と再描画操作を実行するため、DOM 操作に対するブラウザの応答は非常にエネルギーを消費します (## を参照) #ブラウザ レンダリング ページ プロセス )

nbsp;html>



    <meta>
    <meta>
    <meta>
    <title>Document</title>



    <div>
        <ul></ul>
    </div>
    <script>
        let ul = document.querySelector(&#39;ul&#39;)
        for (let i = 0; i < 3; i++) {
            let li = document.createElement(&#39;li&#39;)
            li.innerHTML = i + 1
            ul.appendChild(li)
        }
    </script>


Vue がインデックスを一意の識別子として使用できない理由の簡単な分析

また、多くの JS コードは要素を動的に変更してブラウザの再配置を引き起こしており、エネルギー消費が想像できます。一部のノードが変更された場合、それらの変更されたノードをローカルに再配置すると、パフォーマンスが大幅に節約されるのではないでしょうか? ? ? vue が導入した仮想 dom はこの方式を採用しており、以下は vue のコードです

nbsp;html>



    <meta>
    <meta>
    <meta>
    <script></script>
    <title>Document</title>



    <div>
        <ul>
            <item></item>
        </ul>
        <button>change</button>
    </div>

    <script>
        new Vue({
            el: &#39;#app&#39;,
            data() {
                return {
                    list: [1, 2, 3]
                }
            },
            methods: {
                change() {
                    this.list.reverse()
                }
            },
            components: {
                item: {
                    props: [&#39;num&#39;],
                    template: `
            <div>
              {{num}}  
            
          `,
                    name: &#39;child&#39;
                }
            }
        })
    </script>


Vue がインデックスを一意の識別子として使用できない理由の簡単な分析

#変更ボタンをクリックしたとき

#ネイティブ js がこのような操作を行うと必然的に並び替えが発生しますが、ページは部分的に変更されるだけですが、Vue は仮想 dom を導入してから消費電力を大幅に節約できましたVue がインデックスを一意の識別子として使用できない理由の簡単な分析

それでは? それは仮想 DOM ですか?

vue では、レンダリング関数を実行する前に仮想ノード ツリーを取得し、その仮想ノード ツリーを使用してページをレンダリングできます。ページ dom ノードが動的に変更されると、レンダリング前に、新しく生成された仮想ノードが最後に生成された仮想ノードと比較され、異なる部分のみがレンダリングされます。各仮想ノードはオブジェクトであり、コンテナーのレイヤーの特性を記述します。以下は、vue コードの変更ボタンをクリックする前の仮想ノード ツリーです。
vndoe = {
    tag: 'ul',
    children: [
        { tag: 'li',key:0, children: [{ vnode: { text: '3' } }] },
        { tag: 'li',key:1, children: [{ vnode: { text: '2' } }] },
        { tag: 'li',key:2, children: [{ vnode: { text: '1' } }] }

    ]
}复制代码

変更をクリックすると、新しい仮想ノード ツリーが生成され、それと比較されます

Vue がインデックスを一意の識別子として使用できない理由の簡単な分析比較後、差分のみが表示されます

では、2 つの仮想ノードの数の差を見つけるにはどうすればよいでしょうか?これには、vue ソース コードの差分アルゴリズムが関係します

#ライフサイクルがマウントされた後、データ ソースが変更される限り、ウォッチャー オブザーバーのコールバックはドライブビューの更新 vm._update(v_rander())Vue がインデックスを一意の識別子として使用できない理由の簡単な分析_update は、差分アルゴリズムで異なる

_patch_ 開始を見つけるために、_patch_ に vnode を生成します。



key は、差分アルゴリズムを作成するための一意の識別子です。より効率的 比較する必要がある 2 つのノードを正確に見つけます

2. では、なぜインデックスをキーとして使用できないのでしょうか

私たちはまだ前のコードを参照してください。 diff アルゴリズムでは、 key は一意の識別子です。 2 つの仮想ノード ツリーを比較すると、比較のために同じキー値が見つかります。 キー値が同じであることが判明した場合、データは異なります。内部が異なる場合、差分アルゴリズムは変更されたと判断し、再レンダリングします。実際には、位置が変更されただけです。これに一意の識別 ID を追加すると、
nbsp;html>    <meta>    <meta>    <meta>    <script></script>    <title>Document</title>    <div>        <ul>            <item></item>        </ul>        <button>change</button>    </div>    <script>        new Vue({            el: &#39;#app&#39;,            data() {                return {                    list: [{                        n: 1,                        id: 0
                    }, {                        n: 2,                        id: 1
                    }, {                        n: 3,                        id: 2
                    }, ]
                }
            },            methods: {                change() {                    this.list.reverse()
                }
            },            components: {                item: {                    props: [&#39;num&#39;],                    template: `
            <div>
              {{num}}  
            
          `,                    name: &#39;child&#39;
                }
            }
        })  </script>复制代码

[変更] をクリックした後の仮想ノード ツリー

#diff アルゴリズムが比較対象として同じキー値を見つけ、キー値は同じだが内部のデータも同じであることが判明した場合同じように、再レンダリングはされませんが、位置が変更され、ブラウザの消費量が大幅に節約されます。そのため、キーとしてインデックスを使用すると、diff での最適化が失敗します (再利用性が低下し、仮想 Dom の本来の意図に違反します)

Vue がインデックスを一意の識別子として使用できない理由の簡単な分析

データ インデックスをキーとして削除することの欠点は、より明らかです

nbsp;html>    <meta>    <meta>    <meta>    <script></script>    <title>Document</title>    <div>        <ul>            <li>                <item></item>            </li>        </ul>        <button>del</button>    </div>    <script>        new Vue({            el: &#39;#app&#39;,            data() {                return {                    list: [1, 2, 3]
                }
            },            methods: {                del() {                    this.list.splice(0, 1)
                }
            },            components: {                item: {                    template: &#39;<div>{{Math.random()}}&#39;
                }
            }
        })    </script>复制代码

#削除ボタンをクリックした後

Vue がインデックスを一意の識別子として使用できない理由の簡単な分析

データを削除すると、配列の特性により、残りのデータの添字インデックスとキーが -1、つまり 2 番目、3 番目に変更されるため、実際には最後の項目が削除されたことがわかりました。データキーは 1,2 から 0,1 に変更され、diff アルゴリズムはキー 0,1 のデータ内容が変更され、キー 3 の内容が削除されたとみなして、最初と 2 を再レンダリングします。 2番目のデータを削除し、3番目のデータを削除しますが、実際には削除します。最初のコンテンツ、2番目、3番目は変更されたキーの値です。 Vue は、サブコンポーネントのテキスト コンテンツを深く比較しません。オブジェクトの外側の層が変更されたことのみを認識できます。キーを使用して比較します。キーが一意でない場合、仮想 DOM ツリーが誤って操作され、正しくレンダリングされません。

(学習ビデオ共有: Web フロントエンド開発基本プログラミング ビデオ)

以上がVue がインデックスを一意の識別子として使用できない理由の簡単な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。