JavaScript - Day10 - DOM

一、DOM介绍

DOM的全拼是:Document Object Model,叫做文档对象模型。

就是使用对象结构操作html文档。例如,改变标签的背景颜色,让标签移动产生动画。。。。

DOM中的顶级对象是document,言外之意,DOM其实是属于BOM的。

二、html基本结构操作 

在控制台显示

1.显示body - document.body

        console.log(document.body)

2.显示html - document.documentElement

        console.log(document.documentElement)

3.显示head - document.head

       console.log(document.head);

4.显示和设置title - document.title

       显示:console.log(document.title);

       设置:console.log(document.title='文档');

三、获取标签 

       在js中,标签的id名,可以当做是变量,直接就能代表这个标签元素,但是,id名可以随便定义,但是变量名不能随便定义,所以使用id名代表标签是有风险的。所以需要通过方法来获取到标签元素,自己定义给变量,可以避免这种风险。

1.使用css选择器获取元素

 (1)语法:document.querySelector('css选择器') 

 (2)获取满足css选择器的第一个元素 - 在控制台显示 - 是一个对象 

 (3)用console.log只能看到标签 ---- 想看到对象使用console.dir

<head>
<style>
    .box {
         width: 100px;
         height: 100px;
         background-color: red;
    }

    [a='b'] {
         width: 200px;
         height: 200px;
         background-color: blue;
    }
</style>
</head>
<body>
    <div class="box">我是盒子1</div>
    <div a='b'>我是盒子2</div>
</body>
<script>
    // 第一种
    var oDiv = document.querySelector('div')
    // console.log(oDiv)
    // 第二种 - 获取盒子2
    var oDiv = document.querySelector("[a='b']")
    // console.log(oDiv)
    // 第三种
    var oDiv = document.querySelector('body div')
    // console.log(oDiv)
    // 第四种
    var oDiv = document.querySelector('body div:first-child')
    console.log(oDiv)
</script>

2.获取集合 

 (1)语法:document.querySelectorAll('css选择器') 

 (2)满足css选择器的所有元素都选中 - 是一个伪数组

 (3)可以遍历、取下标、可以有长度,就是不能使用数组方法

<body>
    <div class="box">我是盒子1</div>
    <div a='b'>我是盒子2</div>
</body>
<script>
    var oDivs = document.querySelectorAll('div') // 是伪数组
    console.log(oDivs); // dom中元素的特性:console.log输出的时候都是标签的样子,不是对象的样子
    console.log(oDivs[0]);
    console.log(oDivs.length); //有下标有长度可以遍历
    oDivs.push(666); // 不能使用数组方法
</script>

3.dom中所有能代表标签的变量,他们的数据类型一定是object

 (1)dom中元素的特性:console.log输出的时候都是标签的样子,不是对象的样子

 (2)第一种 - 看类型的方式

                   console.log(typeof oDivs);    ---------- object

          第二种 - 看类型的方式

                   console.dir(oDivs);    ---------- object ---- 看前面有个小箭头所以就是object类型

          console.log(console);   --------- 看对象里面包含的有哪些东西

4.标签选择器

 (1)语法:getElementsByTagName('css的选择器')

    var oDivs = document.getElementsByTagName('div')
    console.log(oDivs); // 只能获取到集合

5.类名选择器

 (1)语法:getElementsByClassName('css的选择器')

    var oDivs = document.getElementsByClassName('box')
    console.log(oDivs);

6.name属性选择器

 (1)语法:getElementsByName('css的选择器')

    var oDivs = document.getElementsByName('mybox')
    console.log(oDivs);

7.id选择器

 (1)语法:getElementById('css的选择器')

    var oDiv = document.getElementById('myid')
    console.log(oDiv);

注意:上述4种获取标签的方法,除了通过id可以准确获取到元素,别的方法都是只能获取到元素的集合(类数组)

四、操作内容

1.双标签 - 纯文本 - 可设置/可获取

    (1)获取内容

             (1-1)只能获取到纯文本内容 - 标签(伪元素).innerText 

                     var oDiv = document.querySelector('div')  --------  获取所有内容

                     console.log(oDiv)

                     console.log(oDiv.innerText)

              (1-2)获取带有标签的内容 - 标签.innerHTML

                     var oDiv = document.querySelector('div')  --------- 获取所有内容

                     console.log(oDiv)

                     console.log(oDiv.innerHTML)

     (2)设置内容

                     var oDiv = document.querySelector('div')

                     console.log(oDiv);

                     oDiv.innerText = '我是文本本本'  -------- 设置div里的文本内容

                     oDiv.innerHTML = '<b>909090</b>'  -------- 设置div里的带有标签的内容

2.表单标签 - 内容操作使用 - 表单标签.value - 可设置/可获取

     (1)获取内容

                     oInput = document.querySelector('input')   --------- 获取所有内容

                     console.log(oInput.value);

     (2)设置内容

                     oInput.value = '内容不能为空'

3.易混点

    坑1:操作内容,必须是 具体的 标签.属性 来操作,不能是  集合.属性 操作

    坑2:不管是设置文本内容还是带有标签的内容,原本的内容就不见了,被覆盖掉了

五、操作属性 

1.样式是div{样式} ------ 属性是body写在行内

2.标签属性 ----- <标签 键=值> ------ 长在标签上的键值对

    <table width="500" height="300" border="1">
        <tr>
            <td>姓名</td>
            <td>性别</td>
            <td>年龄</td>
        </tr>
    </table>

 (1)获取属性值 - 标签.getAttribute('属性名') - 返回是属性的值

    var oTable = document.querySelector('table') //获取所有内容
    var h = oTable.getAttribute('height')
    console.log(h)

 (2)设置属性值 - 标签.setAttribute('属性名','属性值')

    oTable.setAttribute('cellspacing','0')

 (3)删除属性 - 标签.removeAttrribute('属性名')

    oTable.removeAttribute('border')

3.对象属性 ----- 元素.属性名 = 值;
   console.log(元素.属性名);

4.H5的自定义属性操作

   当给标签添加属性以data-XXX开头时,H5提供了一个快速操作属性的api:

            标签.dataset.XXX // 获取属性的值

六、样式操作

1.设置样式 ----- 标签.style.css的键 = 'css的值' ------ 设置在行内

    var oDiv = document.querySelector('div') //无论获取什么条件,都要先获取他老大
    oDiv.style['background-color'] = 'red'
    oDiv.style.backgroundColor = 'red'

    (1)如果键中包含连字符,就使用['键']或小驼峰书写  

    (2)重复的找到规律了- 键=值  键=值  键=值

    (3)循环如何处理 - 就将这个3个键值对放在一个对象中 - 遍历对象

    var obj = {
        width: '100px',
        height: '50px',
        backgroundColor: '#0f0'
    }
    for(var key in obj) {
        oDiv.style[key] = obj[key]
    }

   (4)封装批量设置标签样式的函数

    function setStyle(ele, obj) {
        for (var key in obj) {
            ele.style[key] = obj[key]
        }
    }
    setStyle(oDiv, {
        width: '200px',
        height: '100px',
        backgroundColor: '#f00',
        border: '1px solid #000'
    })

2.获取样式 ----- window.getComputedStyle(标签) ------ 返回(获取)一个用所有css键值对组成的对象

    console.log(getComputedStyle(oDiv));
    console.log( getComputedStyle(oDiv).width );

   (1)点击div小盒让宽度渐变加到500

    var oDiv = document.querySelector('div')
    oDiv.style.width = '100px'
    oDiv.style.height = '100px'
    oDiv.style.backgroundColor = '#f00'
    console.log(getComputedStyle(oDiv))
    console.log(getComputedStyle(oDiv).width)
    oDiv.onclick = function(){
        // 变大 - 设置定时器
        var time = setInterval(
            function(){
            // 获取原来的值
            var obj = getComputedStyle(oDiv);
            var width = obj.width
            width = parseInt(width)
            // 加大
            width += 2
            // 限定最大值
            if(width>=500){
                width=500
                clearInterval(time)
            }
            // 给div加宽 - 重新设置宽度样式,值比原来的大
            oDiv.style.width = width +'px'
            console.log(width)
        },16)
    }

七、类名操作

1.直接操作class属性

   (1)获取标签类名 - 语法:标签.className

   (2)设置标签类名 - 语法:标签.className = 值

   (3)清空所有标签类名 - 语法:标签.className = ' '

    var oDiv = document.querySelector('div')
    document.querySelector('button').onclick = function () {
//      (1)获取标签类名
//      语法:标签.className
        var cname = oDiv.className + ' border'
        oDiv.className = cname
//      (2)设置类名
//      语法:标签.className = 值 
        oDiv.className = 'border'
//      (3)清空所有类名
        oDiv.className = ''
    }

2.利用方法

     语法:标签.classList --- 包含所有类名操作方法的对象

   (1)添加类名 - oDiv.classList.add(新类名)

   (2)删除类名 - oDiv.classList.remove(被删除的类名)

   (3)让一个类名在添加和删除之间切换  -  标签.classList.toggle(类名)

   (4)控制台判断某个类名是否存在 - 标签.classList.contains(类名)

    var oDiv = document.querySelector('div')
    document.querySelector('button').onclick = function () {
        console.log(oDiv.classList);
//      (1)添加类名 - oDiv.classList.add(新类名)
        oDiv.classList.add('border')
//      (2)删除类名 - oDiv.classList.remove(被删除的类名)
        oDiv.classList.remove('box')
//      (3)让一个类名在添加和删除之间切换 -   标签.classList.toggle(类名)
        oDiv.classList.toggle('box')
//      (4)控制台判断某个类名是否存在 - 标签.classList.contains(类名)
        console.log( oDiv.classList.contains('box') );
        console.log( oDiv.classList.contains('border') );
    }

八、页面卷去的距离

1.适用于有文档声明的时候:var t = document.documentElement.scrollTop

2.当没有文档的时候,使用另外一种获取方法:var t = document.body.scrollTop ------  <!DOCTYPE html>

3.兼容写法:不管有没有文档声明都可以获取到的方式 --- 能获取能赋值

   var t = document.documentElement.scrollTop || document.body.scrollTop

九、短路运算

1.语法:var 变量 = 数据1 && 数据2

             (1)当数据1为true,不能决定整个条件的结果,还需要进行到数据2,所以此时会将

                                                                                                                  数据2赋值给变量。

             (2)当数据1为false,就已经知道整个条件的结果了,就没有必要进行到数据2了,所

                                                                                                   以此时会将数据1赋值给变量

2.语法:var 变量 = 数据1 || 数据2

             (1)当数据1为true,就已经能决定整个条件的结果了,就没有必要进行数据2了,此

                                                                                                           时就将数据1赋值给变量

             (2)当数1为false,还不能决定整个条件的结果,需要进行到数据2,此时就会将数据2

                                                                                                                                    赋值给变量

3.利用逻辑运算中的&&||让赋值操作变得更灵活,并带有选择性。

4.可以用于赋值 - 看代码是否能进行到最后(符号的右边),如果能进行到右边就将右边的值赋值给变量,如果只进行到左边就将左边的值赋值给变量

    (1)var a = true || false ---- a的值是左边的值

    (2)var a = false || true ---- a的值是右边的值

    (3)var a = true && false ---- a的值是右边的值

    (4)vafr a = false && true ---- a的值是左边的值

                   如果值不是布尔值,就转成布尔值

5.利用逻辑运算,查看左边的结果能否决定整体的结果

练习:

    var a = 1 && 2 //左边为ture不够,也要右边为ture,所以执行到右边
    console.log(a)


    var a = null || 666; //左边为false还不够 - || 或者运算符 - 有一边为真才可以得到结果 
    console.log(a)


    var a = false && 8
    console.log(a)


    function cb(fn){
        fn&&fn() //左边为undefined - 为false,所以整个为假,不用进行后面了,所以fn没调用,
                                                                     // 直接显示666
        alert(666)
    }
    cb()


    function cb(fn){
        fn&&fn() //只左边为真还不够 - 所以执行到了右边,最终输出右边的结果888,后又输出左边
                                                                       // 结果666
        alert(666)
    }
    cb(function(){
        alert(888)
    })

案例:

  1. 随机点名

  2. 实时显示当前时间

  3. 全选全不选案例

十、节点操作

        DOM 就是我们 html 结构中一个一个的节点构成的。不光我们的标签是一个节点,我们写的文本内容也是一个节点,注释,包括空格都是节点。

        DOM节点分三种:元素节点、文本节点、属性节点。元素节点就是我们获取到的标签元素;标签里面的文本就是文本节点、标签上的属性就是属性节点。

1.根据标签之间的关系获取标签

(1)获取所有儿子 - 父.children

    var ul = document.querySelector('ul')
    console.log(ul.children);

(2)获取第一个儿子 - 父.firstElementChild

    var ul = document.querySelector('ul')
    var first = ul.firstElementChild
    console.log(ul.firstElementChild);

(3)获取最后一个儿子 - 父.lastElementChild

    var ul = document.querySelector('ul')
    var last = ul.lastElementChild
    console.log(ul.lastElementChild);

(4)获取父标签 - 子.parentElement

    var ul = document.querySelector('ul')
    var last = ul.lastElementChild // 借助最后一个儿子
    console.log(last.parentElement);

(5)获取哥哥 - 弟弟.previousElementSibling

    var ul = document.querySelector('ul')
    console.log(ul.children);
    var first = ul.firstElementChild
    var last = ul.lastElementChild
    console.log( last.previousElementSibling );

(6)获取弟弟 - 哥哥.nextElementSibling

    var ul = document.querySelector('ul')
    console.log(ul.children);
    var first = ul.firstElementChild
    var last = ul.lastElementChild
    console.log( first.nextElementSibling );

2.创建标签

(1)语法:document.createElement('标签名字符串')

    var strong = document.createElement('strong')
    strong.innerText = '加粗文本'
    console.log(strong)

3.插入节点

(1)给父追加一个子 - 将这个标签作为某个父标签的最后一个儿子

         语法:父.appendChild()

    var ul = document.querySelector('ul')
    var a = document.createElement('a')
    ul.appendChild(a)

(2)将标签放在某个父标签的某个子标签的前面

         语法:父.insertBefore(新的子, 旧的子)

    var ul = document.querySelector('ul')
    var a = document.createElement('a') 
    a.innerText = '我是a标签'
    ul.appendChild(a)
    var i = document.createElement('i')
    i.innerText = '文本倾斜'
    ul.insertBefore(i,a)

4.替换标签

   语法:父.replaceChild(新, 旧)

    var ul = document.querySelector('ul')
    var a = document.createElement('a') 
    a.innerText = '我是a标签'
    ul.appendChild(a)
    var u = document.createElement('u')
    u.innerText = '下划线'
    ul.replaceChild(u,a)

5.复制(克隆)节点

(1)复制空壳 --- 语法:标签.cloneNode() 

    var u = document.createElement('u')
    u.innerText = '下划线'
    console.log(u)
    var newU = u.cloneNode()
    console.log(newU)

(2)带内容的复制 --- 语法:  标签.cloneNode(true)

    var u = document.createElement('u')
    u.innerText = '下划线'
    console.log(u)
    var newU = u.cloneNode(true)
    console.log(newU)

6.删除节点

   语法:父.removeChild(子)

    var ul = document.querySelector('ul')
    var p = document.createElement('p')
    p.innerText = '我是p标签'
    ul.appendChild(p)
    ul.removeChild(p)

  删除标签案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <table border=1 width="500">
        <thead>
            <tr>
                <th>姓名</th>
                <th>年龄</th>
                <th>性别</th>
                <th>成名绝技</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
    
        </tbody>
    </table>
</body>
<script>
var arr = [
    {
        name:"令狐冲",
        age:20,
        sex:"男",
        skill:"独孤九剑"
    },
    {
        name:"东方不败",
        age:50,
        sex:"女",
        skill:"葵花宝典"
    },
    {
        name:"任我行",
        age:55,
        sex:"男",
        skill:"吸星大法"
    }
];

// 创建表格
var tbody = document.querySelector('tbody')
renderHTML()
function renderHTML() {
    var str = ''
    for(var a = 0; a < arr.length; a++) {
        str += '<tr>'
        var obj = arr[a]
        for(var key in obj) {
            str += '<td>'+obj[key]+'</td>'
        }
        str += '<td>删除</td>'
        str += '</tr>'
    }
    tbody.innerHTML = str   
}

// 获取所有的删除td
bindEvent()
function bindEvent() {
    var tds = document.querySelectorAll('td:last-child')
    for(var b = 0; b < tds.length; b++) {
        (function(b) {

            tds[b].onclick = function() {
                tds[b].parentElement.parentElement.removeChild(tds[b].parentElement)
            }

        })(b)
    }
}
</script>
</html>

十一、获取标签大小(尺寸)

1.包含边框大小

<head>
<style>
    *{
        padding: 0;
        margin: 0;
    }
    div{
        width: 100px;
        height: 150px;
        padding: 10px;
        border: 16px solid #000;
        margin: 20px;
    }
</style>
</head>
<script>
    var div = document.querySelector('div')
</script>

    (1)标签.offsetWidth

    (2)标签.offsetHeight

    var w1 = div.clientWidth
    var h1 = div.clientHeight
    console.log(w1,h1);

2.不包含边框大小 

    (1)标签.clientWidth

    (2)标签.clientHeight

    var w2 = div.offsetWidth
    var h2 = div.offsetHeight
    console.log(w2,h2);

  返回纯数字

十二、获取标签位置

1.标签.offsetLeft

2.标签.offsetTop

<head>
<style>
.box>div>div{
    width: 100px;
    height: 100px;
    background-color: #f00;
    margin: 50px;
}
.box{
    width: 500px;
    height: 500px;
    border: 1px solid #000;
    position: relative;
}
.box2{
    width: 300px;
    height: 300px;
    background-color: #0f0;
}
</style>
</head>
<body>
<div class="box">
    <div class="box2">
        <div></div>
    </div>
</div>
</body>
<script>
var div = document.querySelector('.box div div')
// 位置获取    标签.offsetLeft     标签.offsetTop
var l = div.offsetLeft
var t = div.offsetTop
console.log(l, t);
// 参考设置过定位的祖宗标签,如果祖宗没有定位,就参考html标签
</script>

 获取的是相对于设置过定位的父标签的左边距和上边距离,返回纯数字。

十三、获取标签的边框厚度

1.标签.clientLeft - 获取左边框厚度 

2.标签.clientTop - 获取上边框厚度 

<head>
<style>
*{
    padding: 0;
    margin: 0;
}
div{
    width: 100px;
    height: 100px;
    padding: 10px;
    border-left: 10px solid #000;
    border-top: 20px solid #0f0;
    border-right: 30px solid #00f;
    border-bottom: 40px solid #f00;
    margin: 20px;
}
</style>
</head>
<body>
<div></div>
</body>
<script>
var div = document.querySelector('div')
// 标签.clientLeft    标签.clientTop -- 获取左边框和上边框厚度
console.log( div.clientLeft );
console.log( div.clientTop );
// 标签.tagName   --  大写的标签名
console.log(div.tagName);
</script>

 获取到的是上边框和左边框的厚度,纯数字。

十四、获取标签名

标签.tagName ---- 大写的标签名(控制台)  -----------   ↑↑↑(看十三)

十五、回流/重排 和 重绘

       我们在做案例的时候,通常一个标签要设置很多样式。为了方便我们批量设置样式,可以封装一个批量设置样式的函数:

function setStyle(ele, styleObj) {
    for(var key in styleObj) {
        ele.style[key] = styleObj[key]
    }
}

       这个函数在批量设置样式的时候,每遍历一次,设置一次样式,每次设置样式都设置在了行内,这样会造成多次回流,影响页面性能。

1.浏览器渲染过程 

    (1)解析html生成DOM树,解析css,生成CSSOM树,将DOM树和CSSOM树结合,生成渲染树;

    (2)根据渲染树,浏览器可以计算出网页中有哪些节点,各节点的CSS以及从属关系 - 回流

    (3)根据渲染树以及回流得到的节点信息,计算出每个节点在屏幕中的位置 - 重绘

    (4)最后将得到的节点位置信息交给浏览器的图形处理程序,让浏览器中显示页面

如图:

    (1)解析html ---- 成dom树

    (2)解析css ---- 成样式规则

               渲染树 ----- 布局 ----- 样式 ----- 规则

2.回流

 (1)回流:英文叫reflow,指的是当渲染树中的节点信息发生了大小、边距等问题,需要重新计算各节点和css具体的大小和位置。当网页需要重新布局的时候,就造成了回流

          例:在css中对一个div修饰的样式中,修饰了宽度、高度等样式,浏览器需要重新计算标签大小,这个计算的过程,就是回流的过程。

容易造成回流的操作:

  • 布局流相关操作

    • 盒模型的相关操作会触发重新布局

    • 定位相关操作会触发重新布局

    • 浮动相关操作会触发重新布局

  • 节点操作

    改变节点的结构或其中的文本结构会触发重新布局。

    对标签进行下面这些属性或方法操作的时候,会强行回流:

    • offsetTop

    • offsetLeft

    • offsetWidth

    • offsetHeight

    • scrollTop

    • scrollLeft

    • scrollWidth

    • scrollHeight

    • clientTop

    • clientLeft

    • clientWidth

    • clientHeight

    • getComputedStyle

  • css

    • width

    • height

    • padding

    • border

    • margin

    • position

    • top

    • left

    • bottom

    • right

    • float

    • clear

    • text-align

    • vertical-align

    • line-height

    • font-weight

    • font-size

    • font-family

    • overflow

    • white-space

3.重绘

 (1)重绘:英文叫repaint,当节点的部分属性发生变化,但不影响布局,只需要重新计算节点在屏幕中的绝对位置并渲染的过程,就叫重绘。比如:改变元素的背景颜色、字体颜色等操作会造成重绘。   当网页需要重新绘画的时候就造成了重绘

 (2)回流的过程在重绘的过程前面,所以回流一定会重绘,但重绘不一定会引起回流。

容易造成重绘操作的css:

  • color

  • border-style

  • border-radius

  • text-decoration

  • box-shadow

  • outline

  • background

4. 优化

        不管是回流还是重绘,都会对浏览器的渲染造成影响,所以我们在项目中,尽量避免回流。

         4-1:样式合并修改

         减少造成回流的次数,如果要给一个节点操作多个css属性,而每一个都会造成回流的话,尽量将多次操作合并成一个,例:

var oDiv = document.querySelector('.box');
oDiv.style.padding = '5px';
oDiv.style.border = '1px solid #000';
oDiv.style.margin = '5px';

         操作div的3个css属性,分别是padding、border、margin,此时就可以考虑将多次操作合并为一次。

         方法1:使用style的cssText - 只回流一次

<body>
    <div></div>
</body>
<script>
var div = document.querySelector('div')
div.style.cssText = 'width: 100px;height: 100px;border: 10px solid #f00;position: absolute;left: 20px;top:50px;'
</script>

         方法二:将这几个样式定义给一个类名,然后给标签添加类名 - 只回流一次

<body>
    <div></div>
</body>
<script>
var div = document.querySelector('div')
setStyle(div, {
    width: '100px',
    height: '100px',
    border: '10px solid #f00',
    position: 'absolute',
    left: '20px',
    top: '50px'
})
function setStyle(ele, obj) {
    var str = ''
    for(var key in obj) {
        str += key + ':' + obj[key] + ';'
    }
    console.log(str);
    ele.style.cssText = str
}
</script>

               (1)标签.style.cssText

               (2)标签.setAttribute('style', '')

               (3)标签.className = ''

         4-2:批量操作dom

                  当对DOM有多次操作的时候,需要使用一些特殊处理减少触发回流,其实就是对DOM的多次操作,在脱离标准流后,对元素进行的多次操作,不会触发回流,等操作完成后,再将元素放回标准流

举例:

<body>
    <ul></ul>
</body>
<script>
for(var a = 0; a < 10; a++){
    var li = document.createElement('li')
    li.innerText = a+1
    ul.appendChild(li)
}         // 造成十次回流 - 这样每次给ul中新增一个li的操作,每次都会触发回流。
</script>

方法一:隐藏ul后,给ul添加节点,添加完成后再将ul显示

<body>
    <ul></ul>
</body>
<script>
var ul = document.querySelector('ul')
ul.style.display = none   // 隐藏后的操作不会造成回流
for(var a = 0; a < 10; a++){
    var li = document.createElement('li')
    li.innerText = a+1
    ul.appendChild(li)
} 
ul.style.display = 'block'  // 显示操作后的ul
</script>

此时,在隐藏ul和显示ul的时候,触发了两次回流,给ul添加每个li的时候没有触发回流。

方法二:创建文档碎片,将所有li先放在文档碎片中,等都放进去以后,再将文档碎片放在ul中

<body>
    <ul></ul>
</body>
<script>
var fg = document.createDocumentFragment()
for(var a = 0; a < 10; a++){
    var li = document.createElement('li')
    li.innerText = a+1
    fg.appendChild(li)  // 此时没有造成回流,因为我在内存玩,和页面没有关系
}
ul.appendChild(fg) // 想让文档碎片里的东西在ul里显示,所以把文档碎片放进小括号内,此时
                // 文档碎片自己玩了一招金蝉脱壳,把碎片里面的东西倒给了小括号,也就是ul
</script>

文档碎片就是一个虚拟的DOM节点。不会在页面中使用,跟真的标签操作起来是一样的,对文档碎片操作不会造成回流。触发了一次回流

方法三:将ul拷贝一份,将所有li放在拷贝中,等都放进去以后,使用拷贝替换掉ul

<body>
    <ul></ul>
</body>
<script>
var newUl = ul.cloneNode(true)
for(var a = 0; a < 10; a++) {
    var li = document.createElement('li')
    li.innerText = a + 1
    newUl.appendChild(li)  // 此时页面中没有造成回流
}
ul.parentElement.replaceChild(newUl, ul)  
</script>

触发了一次回流

知识点补充:创建一个div带有滚动条的

<body>
<div style="width: 20px;">
选正是学校后勤上的一名干事,我上世纪80年代在商中上学时就认识他。那时,我们班的玻璃烂了,选正
老师就用右臂夹着大块玻璃,左手拿着玻璃刀、尺子和玻璃泥等,趁课间很快就将破烂的玻璃换掉,安上
新玻璃。他换玻璃很细致,先量窗框,再裁玻璃,然后将玻璃泥揉成条状,然后装上一寸不多一寸不少的
新玻璃,
</div>
<button>按钮</button>
</body>
<script>
document.querySelector('button').onclick = function() {
    var t = document.documentElement.scrollTop || document.body.scrollTop // 放在这个
                                   // 位置,提前获取,就从800次回流优化到现在的400次回流
    var timer = setInterval(function() {
        // 获取卷去的距离 - 获取
        // var t = document.documentElement.scrollTop || document.body.scrollTop // 获
                                                        // 取800次回流,每次获取都要回流
        // 减小
        t -= 20
        console.log(t);
        // 让滚动条走起来 - 设置
        document.documentElement.scrollTop = document.body.scrollTop = t
        if(t <= 0) {
            clearTimeout(timer)
        }
    }, 20)
}
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值