JS之DOM的操作、DOM新增、DOM删除、DOM替换、查找元素、克隆节点、回流和重绘、文档碎片 fragment
「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」。
一、DOM新增
- innerHTML
- 创建一个文本节点
createTextNode()
创建标签节点createElement( )
插入 : 在最后面插入appendChild()
在指定的元素前面插入insertBefore(要插入的元素 , 指定的元素)
两种方法的区别: var 一个对象oP oP 在创建标签的时候,是一个对象 innerHTML 只能解析字符串 栗子:
<div class="a">
<span>111</span>
</div>
- innerHTML新增:
var oDiv = document.querySelector('.a') ;
oDiv.innerHTML = '<p>666</p>'
创建一个标签 createElement
var oP = document.createElement('p') ;
console.log(oP);
如果这样写:
oDiv.innerHTML = oP ; // 无法解析?
是无法解析的,因为innerHTML 只能解析字符串
- 创建一个文本节点
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删除
remove( )
删除自己和所有的子元素removeChild( )
删除指定的子元素,只能删除儿子,不能删除孙子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、找子元素
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>
打印结果:
可以看到打印出了所有的节点,firstChild打印出第一个节点text
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>
打印结果:
可以看到只获取了标签元素
3、找兄弟元素
previousElementSibling
前一个标签兄弟元素nextElementSibling
后一个标签兄弟previousSibling
前一个兄弟节点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>
打印结果:
五、克隆节点
cloneNode()
克隆节点 , 默认只复制标签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>
打印结果:
六、回流和重绘
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的次数,效率会明显提升。
转载自:https://juejin.cn/post/7069553769532850213