ホームページ >ウェブフロントエンド >jsチュートリアル >Dom ノードを最適化する方法
この記事では、Dom ノードの最適化計画を紹介します。一定の参考値があるので、困っている友達が参考になれば幸いです。
DOM 操作は、ブラウザーの再描画とリフローにつながるため、パフォーマンスに最も大きな影響を与えます。ページ UI への変更が DOM 操作を通じて行われることは誰もが知っています。DOM は多数ありますが、 DOM の操作を容易にするために API が提供されていますが、DOM 操作のコストは非常に高く、ページのフロントエンド コードのパフォーマンスのボトルネックのほとんどは DOM 操作に集中しています。したがって、フロントエンドのパフォーマンスの最適化の主な焦点は、 DOM 操作の最適化です。
ブラウザ レンダリング メカニズム:
ブラウザはページをレンダリングします。
ブラウザは HTML ドキュメントのソース コードを解析し、次に、DOM ツリーを構築し、スタイルが見つかったときにそれを非同期的に計算します。
非同期的に計算されたスタイルは、DOM ツリーと合成されて、レンダー ツリーが構築されます。
レンダー ツリーをレイアウトします。
レンダー ツリーを描画します。
DOM ツリーとレンダー ツリーの違いは、display:none; スタイルを持つノードは DOM ツリーには存在しますが、レンダー ツリーには存在しないことです。ブラウザーはそれを描画した後、js ファイルの解析を開始し、js に基づいて再描画およびリフローするかどうかを決定します。
ページ変更が発生したときに発生する操作:
js はシングルスレッドであるため、再描画とリフローはユーザーの操作をブロックし、Web ページのパフォーマンスに影響します
1、複数の dom スタイルを変更し、スタイルの代わりにクラスを使用して、リフローと再描画の複数のトリガーを削減します
例: dom 要素の幅と高さを変更します
var dom = document.getElementById('box') dom.style.width = '300px' dom.style.height = '300px'//访问了三次dom,触发了两次回流和两次重绘
最適化後:
.change { width: 300px; height: 300px; } document.getElementById('p').className = 'change'//只触发一次
2. リスト タイプをバッチで変更し、ドキュメント フローから切り離して復元します。display:none; スタイルを持つノードは DOM ツリーには存在しますが、レンダリング ツリーには存在せず、再描画リフローは発生しません。 。
DOM コレクション内の各 DOM 子ノードにクラスを追加する場合は、各ノードをトラバースしてクラスを追加することで、複数の再描画とリフローをトリガーできます。 #3. DocumentFragment
Virtual DOM は実際にはオブジェクトです. js は空の仮想ノード オブジェクトを作成するための reateDocumentFragment() メソッドを提供します. DocumentFragment ノードはドキュメント ツリーに属しません. 複数の DOM 要素がある場合を追加する必要がある場合、これらの要素を最初に DocumentFragment に追加し、次に DocumentFragment オブジェクトをレンダリング ツリーに追加すると、ページが DOM をレンダリングする回数が減り、効率が大幅に向上します。
/* //需要加入的样式 .change { width: 300px; height: 300px; } */ var ul = document.getElementsByTagName('ul') var lis = document.getElementsByTagName('li') ul.style.display = 'none' for(var i = 0; i < lis.length; i++) { lis[i].className = 'change'; } ul.style.display = 'block'
その他
var frag = document.createDocumentFragment() //创建一个虚拟节点对象 for(var i = 0; i < 10; i++) { var li = document.createElement("li") li.innerHTML = '我是第' + i + 1 + '个元素' frag.appendChild(li) //将li元素加到虚拟节点对象上 } ul.appendChild(frag) //将虚拟节点对象加到ul上2. ループ内の最適化により dom 操作の回数が削減されます
// 事件委托前 var lis = document.getElementsByTagName('li') for(var i = 0; i < lis.length; i++) { lis[i].onclick = function() { console.log(this.innerHTML) }} // 利用浏览器事件通过父元素委托事件给子元素 var ul = document.getElementsByTagName('ul')ul.onclick = function(event) { //也可以做判断给指定的子元素绑定事件 console.log(event.target.innerHTML)};こうやってみるとキャッシュノードの効果を体感できません以下の例を参照してください
//例子1:减少在计算过程中操作dom // 优化前,访问了好多次dom,这些都是细节问题,有经验的绕过,小白平常多注意就行 for(var i = 0; i < 10; i++) { document.getElementById('el').innerHTML += '1'} // 优化后 var str = ''for(var i = 0; i < 10; i++) { str += '1'}document.getElementById('el').innerHTML = str/3. セレクターの違い
##要素を取得する最も一般的な方法は、getElementsByXXX() と queryselectorAll() の 2 つです。これら 2 つのセレクターの違いは非常に大きく、前者は動的コレクションを取得すること、後者は静的コレクションを取得することです
//不缓存 var ps = document.getElementsByTagName("p"), i, p; for( i=0; i<ps.length; i++ ){ p = document.createElement("p"); document.body.appendChild("p"); }造成死循环,每次执行for循环都会动态获取ps的长度,而我们每次进入循环都增加了一个DOM(p),ps的长度也+1. //缓存 var ps = document.getElementsByTagName("p"), i, p,len; for( i=0;len=ps.length;i<len; i++ ){ p = document.createElement("p"); document.body.appendChild("p"); }//使用变量保存ps的长度。
静的コレクションの操作ではドキュメントの再クエリが発生しません。動的コレクションよりも最適化されています。
推奨学習:
以上がDom ノードを最適化する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。