栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > Web开发 > JavaScript

布局与重排

JavaScript 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

布局与重排

布局

在进行 DOM 节点和样式规则匹配的同时,渲染引擎会为每一个可视节点创建 LayoutObject 对象。LayoutObject 对象保存了该节点所需要的布局信息,比如位置( 包含块模型 )、大小( 盒子模型 )等等。整个计算流程大致可以分为以下 4 步:

  1. 判断该节点是否需要重新布局,如果需要,创建 LayoutObject 对象;
  2. 计算该节点的宽度和垂直方向的外边距,更新 LayoutObject 对象;
  3. 遍历该节点的每一个子节点,依次计算它们的布局;
  4. 根据子节点的布局结果,计算该节点的高度,并最终返回 LayoutObject 对象。

*节点的高度计算,会依据节点类型的不同而采用不同的算法,例如块级元素,定义了自身的宽高,那么就可以据此来确定节点的高度( 期间可能还涉及到溢出时的展示效果 );而内联元素,则需要根据子节点的的大小来确定节点的高度。因此,布局计算通常会采用先确定宽度,再根据子节点的计算结果,确定高度的顺序进行。

渲染引擎的实际布局计算过程,远比我列举的 4 步更为复杂。至于如何做到最高效的计算,这是留给引擎开发者的终极任务,作为前端开发者,简单理解:DOM + CSSOM = LayoutObject。

例子:


    body {
 margin: 0;
 padding: 5px;
    }
    
    div {
 width: 40px;
 height: 40px;
 margin: 5px;
    }
    
    span {
 font-size: 16px;
    }



    
    hello

例子中 DOM 和 CSSOM 结合之后,创建出以下 LayoutObject:

body + { width:764px; height: 60px; } = LayoutBlock{ BODY } at( 0,0 ) size( 764*60 )
div + { width:40px; height: 40px; } = LayoutBlock{ DIV } at( 5,5 ) size( 50*50 )
span + { width:37px; height: 20px; } = LayoutInline{ SPAN } at( 5,55 ) size( 37*20 )

*例子中没有设定位置的 CSS 样式,因此全部按照正常流去理解定位。节点大小不够准确,仅供学习。

重排

在布局计算的第一步,就是判断是否需要重新布局。那么,有哪些情况会导致重新布局( 重排 )呢?

首先,网页被初次打开,一定会发生布局计算。

其次,Javascript 代码通过 DOM、CSSOM 修改节点,致使元素的几何空间发生变化。

最常见的情况有如下几种:

  1. 添加或删除节点;
  2. 节点的位置发生变化( 浮动、定位 );
  3. 节点的大小发生变化( 内容、内外边距和边框宽度 )。

最后,scroll 事件、resize 事件、网页动画( 主要指 Javascript 动画 )等会造成密集的重排,可能会出现网页卡顿现象。

减少重排的常用方法

重排是比较耗时的,而且,一旦布局发生变化,就会发生重排。我们在实际工作中,可以从以下两个方向,减少重排的发生:

批量修改 DOM

1、使用 display:none 隐藏节点,进行多次修改之后再显示。

例子:



var showBox = (function() {
    var div = document.createElement("div");
    div.innerHTML = "hello";
    div.style.display = "none";
    document.body.appendChild(div);
    return div;
})();

document.querySelector("button").onclick = function() {
    showBox.style.display = "block";
}

2、使用文档片段( documentFragment )构建子树,构建完毕之后,添加进 DOM 模型。

例子:



var showList = (function() {
    var ul = document.createElement("ul"),
 docF = document.createdocumentFragment();

    ["A", "B", "C"].forEach(function(v) {
 var li = document.createElement("li");
 li.innerHTML = v;
 docF.appendChild(li);
    });
    ul.appendChild(docF);
    return ul;
})();

document.querySelector("button").onclick = function() {
    document.body.appendChild(showList);
}

3、使用 innerHTML 和 outerHTML 批量替换 HTML 元素。

例子:




var showList = (function() {
    return ul_HTML = "
  • A
  • B
  • C
"; })(); document.querySelector("button").onclick = function() { document.querySelector("div").innerHTML = showList; }

*innerHTML 和 outerHTML 的实现原理,其实也是将字符串经过词法、语法分析之后,通过 documentFragment 构建子树,并最终添加进 DOM 模型。

批量修改样式

1、使用 className 批量修改节点的样式。

例子:

 
    p {
 font-size: 20px;
 color: blueviolet;
 border: 1px solid #ccc;
    }
    
    .p_style {
 font-size: 30px;
 color: brown;
 border: 2px solid #ccc;
    }



hello

2、另外一个比较不常用的,就是使用 cssText 批量修改样式。

例子:

 
    p {
 font-size: 20px;
 color: blueviolet;
 border: 1px solid #ccc;
    }



hello

Render 树

经过渲染引擎的处理,LayoutObject 对象保存了 DOM 节点以及其对应的布局信息,LayoutObject 对象已经知道了该如何绘制自己。然后,该对象会带着这些信息,插入到 Render 树上。

Render 树按照 DOM 树的排版规则进行排版,但两者并非一一对应的关系,只有 document 节点和可视节点才会出现在 Render 树中。

Render 树可以看作是渲染引擎为最后绘图,而构建的内部表示对象。但实际情况可能更为复杂。因为 HTML5 的出现,让绘图不再是简单地应对 HTML 元素,还有 2D、3D 图形,多媒体等等。


如有错误,欢迎指正,本人不胜感激。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/244613.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号