1.document.write和innerHtml
document.write // 重排整個頁面
innerHtml //重繪頁面的某些部分
2.DOM樹和渲染樹
DOM樹:表示頁面結構
渲染樹:表示DOM節點如何顯示
3.重排和重繪
重排:當DOM元素影響了元素的**幾何屬性**(例如寬和高),浏覽器需要重新計算元素的幾何屬性,
同樣其它元素的幾何屬性也會和位置也會是以受到影響。浏覽器會使渲染樹中受到影響的
部分失效,并重新構造渲染樹。
重繪:完成重排後,浏覽器會重新繪制受影響的部分到螢幕上中。
重排發生的情況:
- 頁面渲染器初始化。
- 添加或删除可見的DOM元素。
- 元素位置改變。
- 元素的尺寸改變(包括:内外邊距、邊框厚度、寬度、高度等屬性的改變)。
- 内容改變。
- 浏覽器視窗尺寸改變。
- 讀取某些元素屬性:(offsetLeft/Top/Height/Width, clientTop/Left/Width/Height, scrollTop/Left/Width/Height, width/height, getComputedStyle(), currentStyle(IE))
觸發重排的屬性
有些節點,當你改變他時,會需要重新布局(這也意味着需要重新計算其他被影響的節點的位置和大小)
這種情況下,被影響的DOM樹越大(可見節點),重繪所需要的時間就會越長,是以需要盡力避免這些屬
性。
一些常用的改變時會觸發重布局的屬性:
盒子模型相關屬性會觸發重布局:
- width
- height
- padding
- margin
- display
- border-width
- border
- min-height
定位屬性及浮動也會觸發重布局:
- top
- bottom
- left
- right
- position
- float
- clear
改變節點内部文字結構也會觸發重布局:
- text-align
- overflow-y
- font-weight
- overflow
- font-family
- line-height
- vertival-align
- white-space
- font-size
重繪發生的情況
重繪發生在元素的可見的外觀被改變,但并沒有影響到布局的時候。比如,僅修改DOM元素的
字型顔色(隻有Repaint,因為不需要調整布局)
觸發重繪的屬性
修改時隻觸發重繪的屬性有:
- color
- border-style
- border-radius
- visibility
- text-decoration
- background
- background-image
- background-position
- background-repeat
- background-size
- outline-color
- outline
- outline-style
- outline-width
- box-shadow
注意:重排一定會引起重繪,但重繪不一定會引起重排。重排和重繪都會影響浏覽器性能。
優化
1.改變元素的className
例如:
// css
.active {
padding: 5px;
border-left: 1px;
border-right: 2px;
}
// javascript
var el = document.querySelector('.el');
el.className = 'active';
2.需要批量建立或修改多個DOM節點時:
1)隐藏元素,進行修改後,然後再顯示該元素
例如:
let ul = document.querySelector('#mylist');
ul.style.display = 'none';
appendNode(ul, data);
ul.style.display = 'block';
先将ul設定為display:none;然後進行頁面布局等操作;設定完成後将元素設定為
display:block;這樣的話就隻引發兩次重繪和重排,分别是控制元素的顯示與隐藏。
2)使用文檔片段建立一個子樹,然後再拷貝到文檔中
例如:
let fragment = document.createDocumentFragment();
appendNode(fragment, data);
ul.appendChild(fragment);
文檔片段是一個輕量級的document對象,它設計的目的就是用于更新,移動節點之類的任務,
而且文檔片段還有一個好處就是,當向一個節點添加文檔片段時,添加的是文檔片段的子節點群,
自身不會被添加進去,這樣隻會觸發一次重排。
3)将原始元素拷貝到一個獨立的節點中,操作這個節點,然後覆寫原始元素
例如:
let old = document.querySelector('#mylist');
let clone = old.cloneNode(true);
appendNode(clone, data);
old.parentNode.replaceChild(clone, old);
這種方法也是隻有一次重排
3.緩存布局資訊
4.将需要多次重排的元素,position屬性設為absolute或fixed,元素脫離了文檔流,
它的變化不會影響到其他元素;
5.盡量不要使用table布局。