likes
comments
collection
share

JS之DOM的操作、DOM新增、DOM删除、DOM替换、查找元素、克隆节点、回流和重绘、文档碎片 fragment

作者站长头像
站长
· 阅读数 24

「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」。

一、DOM新增

  1. innerHTML
  2. 创建一个文本节点 createTextNode() 创建标签节点 createElement( ) 插入 : 在最后面插入 appendChild() 在指定的元素前面插入 insertBefore(要插入的元素 , 指定的元素)

两种方法的区别: var 一个对象oP oP 在创建标签的时候,是一个对象 innerHTML 只能解析字符串 栗子:

	<div class="a">
        <span>111</span>
    </div>
  1. innerHTML新增:
 		var oDiv = document.querySelector('.a') ;
        oDiv.innerHTML = '<p>666</p>'

创建一个标签 createElement

		var oP = document.createElement('p') ;
        console.log(oP);

如果这样写:

oDiv.innerHTML = oP ;   // 无法解析?

是无法解析的,因为innerHTML 只能解析字符串

  1. 创建一个文本节点
		var oText = document.createTextNode('666');
        console.log(oText);

添加子元素 把文本插入标签中

oP.appendChild(oText) ;

把p插入div中

oDiv.appendChild(oP)

*注:同一个标签只能操作一次 --- 标签是对象,对象都有唯一的地址

在span标签前插入p标签

		var oSpan = document.querySelector('span') ;
        oDiv.insertBefore(oP , oSpan)

二、DOM删除

  1. remove( ) 删除自己和所有的子元素
  2. removeChild( ) 删除指定的子元素,只能删除儿子,不能删除孙子
  3. innerHTML = ' ' 删除所有的子元素
<body>
    <div class="a">
        <p>11</p>
        <span>22</span>
        <h2>
            <i>888</i>
        </h2>
    </div>
    <script>      
        var oDiv = document.querySelector('.a') ;
        // oDiv.remove() //删除自己和所有的子元素

        var oP = document.querySelector('p') ;
        oDiv.removeChild(oP) //删除指定的子元素

        // oDiv.innerHTML = '' //删除所有的子元素
        var oI = document.querySelector('i') ;
        oDiv.removeChild(oI) // 报错 --- removeChild() 只能删除儿子,不能删除孙子
    </script>    
</body>

三、DOM替换

替换子元素 replaceChild(new , old)

<body>
    <div class="a">
        <p>11</p>
        <span>22</span>
        <h2></h2>
    </div>
    <script>
        var oDiv = document.querySelector('.a') ;
        var oSpan = document.querySelector('span') ;

        var oStrong = document.createElement('strong') ;
        oStrong.innerHTML = '888'

        oDiv.replaceChild(oStrong , oSpan) //用oStrong替换oSpan
    </script>    
</body>

四、查找元素

1、找父元素 parentNode

<body>

    <ul>
        <li>
            <p>11</p>
            <button>111</button>
        </li>
        <li>
            <p>22</p>
            <button>222</button>
        </li>
        <li>
            <p>33</p>
            <button>333</button>
        </li>
    </ul>

    <script>

        // 找父元素   parentNode

        var oBtns = document.querySelectorAll('button') ;
        for(var i = 0 ; i < oBtns.length ; i++) {
            oBtns[i].onclick = function () {  
                console.log(this.parentNode); //找到当前点击对象的父元素,当前点击对象是button,父元素为li
                
            }
        }

    </script>
    
</body>

2、找子元素

  1. childNodes :子节点 --- 包含所有的文本,换行,标签,注释等等
<body>
    <div class="a">
        <!-- 这里是注释 -->
        <p>11</p>
        <span>222</span>
        <h3>333</h3>
    </div>
    <script>
        var oDiv = document.querySelector('.a') ;
        console.log(oDiv.childNodes);
        console.log(oDiv.firstChild);   // 节点
    </script>  
</body>

打印结果: JS之DOM的操作、DOM新增、DOM删除、DOM替换、查找元素、克隆节点、回流和重绘、文档碎片 fragment 可以看到打印出了所有的节点,firstChild打印出第一个节点text

  1. children 子元素 --- 只包含标签
<body>

    <div class="a">
        <!-- 这里是注释 -->
        <p>11</p>
        <span>222</span>
        <h3>333</h3>
    </div>


    <script>
	    //   firstElementChild	第一个子元素

        //   lastElementChild	最后一个子元素

        var oDiv = document.querySelector('.a') ;
        console.log(oDiv.childNodes);

        console.log(oDiv.children); //打印所有元素
        console.log(oDiv.firstElementChild); //第一个子元素
        console.log(oDiv.lastElementChild);   // 标签
        console.log(oDiv.children[0]); //按序号查找子元素

    </script>
    
</body>

打印结果: JS之DOM的操作、DOM新增、DOM删除、DOM替换、查找元素、克隆节点、回流和重绘、文档碎片 fragment 可以看到只获取了标签元素

3、找兄弟元素

  1. previousElementSibling 前一个标签兄弟元素
  2. nextElementSibling 后一个标签兄弟
  3. previousSibling 前一个兄弟节点
  4. nextSibling 后一个兄弟节点

栗子:

<body>
    <div class="a">
        <h1>00</h1>
        <span>11</span>
        <p>22</p>
        <strong>333</strong>
    </div>
    <script>
        var oDiv = document.querySelector('.a') ;
        var oP = document.querySelector('p') ;

        console.log(oP.previousElementSibling);  // 前一个标签兄弟元素span

        console.log(oP.previousSibling);  // 前一个兄弟节点,换行,text

        console.log(oP.nextElementSibling); //后一个标签兄弟, strong

        console.log(oP.nextSibling);  //后一个兄弟节点, 换行,text


        console.log(oP.previousElementSibling.previousElementSibling);

    </script>
    
</body>

打印结果: JS之DOM的操作、DOM新增、DOM删除、DOM替换、查找元素、克隆节点、回流和重绘、文档碎片 fragment

五、克隆节点

  1. cloneNode() 克隆节点 , 默认只复制标签
  2. cloneNode(true) 克隆节点,包含子元素
<body>
    <div class="a">
        <p>222</p>
    </div>
    <script>
        var oDiv = document.querySelector('.a') ;

        var oDiv2 = oDiv.cloneNode(true) ;//克隆节点,包含子元素
        console.log(oDiv2);
        
        var oDiv3 = oDiv.cloneNode() ;//克隆节点 , 默认只复制标签
        console.log(oDiv3);
        
        document.body.appendChild(oDiv2)
        document.body.appendChild(oDiv3)
    </script>  
</body>

打印结果: JS之DOM的操作、DOM新增、DOM删除、DOM替换、查找元素、克隆节点、回流和重绘、文档碎片 fragment

六、回流和重绘

1、基本概念

  • 回流 当render树中的一部分或者全部因为大小边距、元素的规模尺寸,布局,隐藏等问题发生改变而需要重建的过程叫做回流(改变大小)。
  • 重绘 每个页面至少需要一次回流,就是在页面第一次加载的时候。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘。

*注:回流必引发重绘,但是重绘不一定引发回流。回流的代价大于重绘, 重绘和回流是无法避免的。这个问题只能优化,不能解决。任何的DOM操作都会引发回流

1、回流发生条件

当页面布局和几何属性改变时就需要回流。下述情况会发生浏览器回流: (1)添加或者删除可见元素;

(2)元素位置改变;

(3)元素尺寸改变——边距、填充、边框、宽度和高度

(4)内容发生改变(文字数量或图片大小等等)

(5)页面第一次渲染 在页面发生首次渲染的时候,所有组件都要进行首次布局,这是开销最大的一次回流。

(6)浏览器窗口尺寸改变——resize事件发生时

(7)激活CSS伪类(例如::hover)

(8)设置style属性

2、重绘发生条件

当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如: visibility、outline、背景色等属性的改变。

七、文档碎片 fragment

DOM规定文档片段(document fragment)是一种“轻量级”的文档,可以包含和控制节点,但不会像完整的文档那样占用额外的资源。它可以包含各种类型的节点,在创建之初是空的。它有一个很实用的特点,当请求把一个DocumentFragment节点插入文档树时,插入的不是DocumentFragment自身,而是它的所有子孙节点。

可以将文档片段作为一个“仓库”来使用,即可以在里面保存将来可能会添加到文档中的节点。它还有利于实现文档的剪切、复制和粘贴操作。

栗子:

<body>

    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
    </ul>

    <script>
        // 文档碎片 fragment
        var fragment = document.createDocumentFragment() ;//创建一个文档碎片
        console.log(fragment);//获取到#document-fragment

        for(var i = 0 ; i < 10 ; i++) {
            var oP = document.createElement('p') ; //创建p标签
            oP.innerHTML = i ;//在p标签中写入i
            fragment.appendChild(oP)//在文档碎片中插入oP对象(一共10个)
        }
        document.body.appendChild(fragment)//将fragment插入到body中
    </script>
    
</body>

这样写是为了优化页面的重绘和回流。当需要添加多个dom元素时,如果先将这些元素添加到DocumentFragment中,再统一将DocumentFragment添加到页面,会减少页面渲染dom的次数,效率会明显提升。