前言
本文总结了一些常用的 DOM 操作,主要是为了方便平时开发过程中的 api 查阅,记性不好老是容易健忘,刚好借此机会总结一波 🤣
什么是DOM
每个载入浏览器的 HTML 文档都会成为 Document 对象。
DOM(文档对象模型)是一种表示和操作HTML和XML文档的标准编程接口。它将文档解析为由节点和对象(包括元素,属性和文本)组成的树形结构,允许开发人员使用编程语言(如JavaScript)来操作文档的内容,结构和样式。
通过DOM,我们可以使用 JavaScript 来访问和修改文档的内容和结构,从而实现动态网页的创建和交互,对用户的操作做出响应。
什么是节点、元素
DOM 将 HTML 文档视作树结构,这种结构被称为节点树。
通过 HTML DOM,节点树中的所有节点都可以通过 JS 进行访问。所有 HTML 元素(节点)均可被修改。
经常使用的节点主要有以下几种类型:
-
Element类型(元素节点):nodeType值为 1
- HTML元素内的文本是文本节点
- 每个HTML属性是属性节点
-
Text类型(文本节点):元素内的文本是文本节点 nodeType值为 3
-
Comment类型(注释节点): 每个注释是注释节点 nodeType值为 8
-
Document类型(document节点):整个文档是一个文档节点 nodeType值为 9
其规定的一些常用的属性:
- 通过 document.body document.head 可以分别获取HTML中的
- document.documentElement为标签
通过一些属性可以来遍历节点树:
-
parentNode -- 获取所选节点的父节点,最顶层的节点为#document
-
childNodes -- 获取所选节点的子节点集合
-
firstChild -- 获取所选节点的第一个子节点
-
lastChild -- 获取所选节点的最后一个子节点
-
nextSibling -- 获取所选节点的后一个兄弟节点 列表中最后一个节点的nextSibling属性值为null
-
previousSibling -- 获取所选节点的前一兄弟节点
- 列表中第一个节点的 previousSibling 属性值为 null
元素
元素(element)是指 HTML 或 XML 中的标签(tag),它们是文档树中的一种节点类型,也是 DOM 中最常用的节点类型之一。这就意味着元素继承自节点,所以它也具备了节点所拥有的属性、方法。
元素所具有属性:
const element = document.getElementById('idName')
element.childNodes
element.firstChild
element.lastChild
element.previousSibling
element.nextSibling
element.parentNode
element.parentElement
获取 DOM
document 对象是一个内置对象,我们可以通过它的许多属性和方法来获取和操作 DOM 。
获取 DOM 的方式:
-
通过 id 获取
- **document.getElementById('idName')
- 由于在页面中标签元素的 id 是唯一的,所以返回的是一个 node 节点
-
通过 name 属性获取
- document.getElementsByName('domName') 返回一个nodeList集合(类数组)
- name 属性是为了方便提交表单数据而打造的,所以 name 属性一般存在于(form表单、表单元素、iframe、img)。
- 设置 name 属性时,会自动在 Document 对象中创建以该 name 属性值命名的属性。所以可以通过document.domName 引用相应的 DOM 对象
-
通过指定的标签名
- document.getElementsByTagName('li') 返回一个nodeList集合(类数组)
- tagName不区分大小写,当tagName为*时,表示选取所有元素
- 该方法只能选取调用该方法的元素的后代元素
-
通过class类名获取
- document.getElementsByClassName(“classNames”) 返回一个nodeList集合(类数组)
- classNames是CSS类名称的组合(多个类名之间用空格隔开且样式名称不分先后顺序)
- getElementsByClassName(“class2 class1”) 将选取同时应用了class1和class2样式的元素
- 该方法只能选取调用该方法的元素的后代元素
-
通过样式选择器获取元素
-
document.querySelectorAll('selector') , 其中selector为合法的CSS选择器,返回一个nodeList集合,没有找到则返回null
-
document.querySelector() 样式选择器,返回符合规则的第一个元素;如果没找到则返回null
-
-
伪元素的获取
- 与DOM元素不同的是,伪元素的本身并不是DOM元素。它并不存在于文档中,所以无法直接通过 js 获取和操作,默认 display 属性为 inline
- 常用的伪元素 除了::after、::before、之外还有 ::first-line、::first-letter、::selection、::backdrop
- 需要通过 window.getComputedStyle(element, ":after") 来获取 DOM 上的伪元素
操作DOM
在页面中操作 DOM 是非常“昂贵”的,所以应该尽量避免频繁的对 DOM 进行操作。
-
新增/插入节点
- 新增创建节点:document.createElement()
- 创建一个文本节点: document.createTextNode('text')
- 插入节点: element.appendChild(被插入的节点)
<div id="wrapper">
</div>
// 获取节点
const wrapper = document.getElementById('wrapper')
// 创建文本节点
const text = document.createTextNode('我是文本')
// 新增节点
const newDiv = document.createElement('div')
newDiv.innerHTML = '我是内容'
// 插入节点
wrapper.appendChild(newDiv)
wrapper.appendChild(text)
被插入的元素
-
获取子元素列表,获取父元素
- 通过 parentNode 属性获取当前节点的父元素
- 通过 childNodes 属性获取元素的子结点 nodeList 集合(类数组)
newDiv.parentNode // 获取所选节点的父节点
wrapper.childNodes // 获取元素的子结点
-
删除子元素
- 删除节点: element.removeChild(节点) 并返回被移除的节点
const removeChild = wrapper.removeChild(newDiv);//移除document对象的方法div1
console.log(removeChild)
-
元素替换
- 替换节点: replaceChild(插入的节点,被替换的节点) ,用于替换节点
- 接受两个参数,第一参数是要插入的节点,第二个是要被替换的节点。返回的是被替换的节点。
const replaceChild = wrapper.replaceChild(text,newDiv);// 替换节点将 newDiv 替换成文本节点
console.log(replaceChild)
属性操作
attribute 是HTML标签中定义的属性(修改html属性,会改变html结构),它的值只能是字符串。
- element.attributes: 返回元素所有属性节点的实时集合,是个类数组对象
- element.getAttributeNames(): 返回一个Array 包含指定元素的所有属性名称
- element.getAttribute(attributeName): 获取元素的属性值
- element.setAttribute(attributeName, value): 设置元素的属性值
- element.removeAttribute('attributeName'): 删除元素对应的属性
- element.hasAttribute(attributeName): 检查元素是否具有指定的属性
- element.hasAttributes(): 检查元素是否具有任何属性。如果元素具有任何属性,则返回 true,否则为 false
所有HTML 元素都有一组默认属性,例如 id、class、style 等。这些属性可以通过上述方法进行操作。
可以通过元素的 src 属性设置图片的地址
const img = document.querySelector('img');
// 设置图片的 src
img.setAttribute('src', 'image.jpg');
// 获取src属性值
const href = img.getAttribute('href');
类的操作
DOM 中同样可以对元素的类名进行操作设置
- element.className -- 获取元素的类名,以字符串的形式返回
- element.classList -- 获取元素的类名列表
className 是一个可读写的属性,可以直接在原有的类名上拼接新的名称,或者通过正则来删除、修改类名
element.className += 'example'
element.className = element.className.replace(/^bold$/, '');
classList 提供了操作类名的方法:
element.classList.add() // 新增一个类名
element.classList.remove() //移除一个指定的类名
element.classList.contains() // 检查当前元素是否包含某个类名
element.classList.toggle() //将某个类名 移入 或 移出 。
element.classList.item() //返回指定索引位置的类名。
element.classList.toString() //将所有类名拼接成字符串。
注意点区分
1. HTML中的 attribute 和 JavaScript中的 property
- attribute 是 HTML 元素在 HTML 中的属性,可以通过 getAttribute 和 setAttribute 方法获取和设置。
- property 是 HTML 元素在 DOM 中的属性,可以看作 DOM 对象的键值对,用点操作符修改,通过 JavaScript 直接访问和修改。
用点操作符修改 property的 value 值,并不会同步到 attribute 上;
但是通过 setAttribute 修改属性值,会同步到 property 上。
在HTML中 我们可以通过以下方式获取和设置 value 属性:
<input type="text" id="myInput" value="Hello World">
<script>
// 通过 attribute 获取 value 属性
const myInput = document.querySelector('#myInput');
const valueAttribute = myInput.getAttribute('value'); // 'Hello World'
// 通过 property 获取 value 属性
const valueProperty = myInput.value; // 'Hello World'
// 通过 property 设置 value 属性
myInput.value = 'New Value';
</script>
虽然 attribute 和 property 定义的属性分别在不同层面上,但是有些属性值是共享的例如:
id、class、lang、dir、title
<div id="div" class="class" lang="lang" dir="dir" title="title" user="user" >
var ele = document.getElementById('id');
// 获取 元素 HTML 上的 属性
console.log(ele.getAttribute('id')) // id
console.log(ele.getAttribute('class')) // class
console.log(ele.getAttribute('lang')) // lang
console.log(ele.getAttribute('dir')) // ltr
console.log(ele.getAttribute('title')) // title
console.log(ele.getAttribute('user')) // user
// 点操作符获取 DOM 上的属性
ele.user1= 'user1'
console.log(ele.id) // id
console.log(ele.className) // class
console.log(ele.lang) // lang
console.log(ele.dir) // ltr
console.log(ele.title) // title
console.log(ele.user1) // user
console.log(ele.user) // undefined
// 点操作符不会同步到 元素 HTML 的 attribute 上
console.log(ele.getAttribute('user1')) // null
但 attribute 和 property 的值并不总是相同的:
-
表单中的单选项,对于 input 元素的 checked 属性,
- 在 HTML 中可以设置为 checked 或者 unchecked;
- 在 JavaScript 中,其值只有 true 和 false 两种情况。
<input type='radio' checked='checked' id='radio'>
<script>
var radio = document.getElementById('radio');
console.log(radio.getAttribute('checked')); // 'check'
console.log(radio.checked); // true
</script>
- img 中的 href 属性,通过不同方式获取到的路径也有所不同
<a href='a.html' id='web'> </a>
<script>
var radio = document.getElementById('web');
console.log(web.getAttribute('href')); // 'a.html'
console.log(web.href); // 绝对路径
</script>
- attribute 取到的是相对路径;
- property 取到的是绝对路径。
attribute 和 property 的使用
再次强调 DOM 的操作非常“昂贵”,所以尽量避免频繁的DOM操作。
使用 property 可以在 js 的机制中避免 DOM 的重新渲染,而 attribute 一旦改了 html 结构,则一定会引起DOM 的重新渲染。
所以尽量使用property。
因此 获取 DOM 元素最新的属性值,应该使用 property,获取 HTML 中的属性值,则应该使用 attribute
建议在以下两种情况中使用attribute:
- 自定义 attribute 标签,因为它不能同步到 property 上。
- 访问内置的 html 标签的 attribute,如 input 的 value(可以用来检验 value 值是否改变)
2. innerText、innerHTML、outText、outHTML
注意区分元素的这几个属性
估计大家在刷面试题的时候也看到过这样的题目:
描述一下 innerText、 innerHTML、outText、outHTML 这几个属性之间的区别
比如:div id="testDiv"><p>Text in DIV</p></div>
先来写一个小小的demo来观察一下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="testDiv"><p>Text in DIV</p></div>
<script>
const testDiv = document.getElementById('testDiv')
console.log('innerHTML -- ', testDiv.innerHTML)
console.log('innerText -- ', testDiv.innerText)
console.log('outerHTML -- ', testDiv.outerHTML)
console.log('outerText -- ', testDiv.outerText)
</script>
</body>
</html>
通过控制台的输出我们可以观察到:
- innerHTML: 用于获取或设置元素的 HTML 内容,可以获取元素的所有子元素、文本和 HTML 标记
- innerText:用于获取或设置元素的文本内容,但不包括 HTML 标记。
- outerHTML:用于获取或设置元素及其所有子元素的 HTML 内容,包括其自身 HTML 标记
- outerText:属性用于获取或设置元素及其所有子元素的文本内容,但不包括 HTML 标记
这些属性支持读取和赋值,但 outerText、nnerText 的区别在于 outerText 赋值时会把标签一起赋值掉。
另外 outerText、innerText 赋值出现HTML标签或者特殊字符时会被转义。
需要注意的是,这些属性在访问或设置时都会重新解析和渲染 HTML 内容,因此在性能方面可能会有一定的影响。
从页面中获取的宽高信息
获取DOM 元素高度:
-
offsetHeight:返回元素的高度,包括元素的边框、内边距和滚动条,但不包括外边距。
- 网页可见区域高: document.body.offsetHeight (包括边线的高)
-
clientHeight: 返回元素的高度,包括元素的内边距,但不包括边框、外边距和滚动条。
- 网页可见区域高: document.body.clientHeight
-
scrollHeight: 返回元素的内容高度,包括被隐藏的部分,但不包括边框、外边距和滚动条。
- 网页正文全文高: document.body.scrollHeight
-
scr ollTop:用于获取或设置滚动条顶部与元素顶部的距离。它适用于所有具有滚动条的元素,例如 window、document 和 div 等。
- 网页被卷去的高: document.body.scrollTop
- document.scrollTop = document.scrollHeight - document.clientHeight
- getBoundingClientRect().height:返回元素的高度,包括元素的边框,但不包括内边距、外边距和滚动条。
- style.height:返回或设置元素的高度,包括内边距和边框,但不包括外边距和滚动条。
DOM 元素的宽度与高度的获取相似
- offsetWidth:返回元素的宽度,包括元素的边框、内边距和滚动条,但不包括外边距。
- 网页可见区域宽: document.body.offsetWidth (包括边线的宽)
-
clientWidth:返回元素的宽度,包括元素的内边距,但不包括边框、外边距和滚动条。
- 网页可见区域宽: document.body.clientWidth
-
scrollWidth:返回元素的内容宽度,包括被隐藏的部分,但不包括边框、外边距和滚动条。
- 网页正文全文宽: document.body.scrollWidth
-
scrollLeft:用于获取或设置滚动条左侧与元素左侧的距离。它适用于所有具有水平滚动条的元素,例如 window、document 和 div 等。
- 网页被卷去的左: document.body.scrollLeft
- getBoundingClientRect().width:返回元素的宽度,包括元素的边框,但不包括内边距、外边距和滚动条。
- style.width:返回或设置元素的宽度,包括内边距和边框,但不包括外边距和滚动条。
这些属性需要注意的是:
- style.width 只能获取或设置内联样式中的宽度值。如果元素使用了外部样式表或者内部样式表,需要使用其他方法来获取宽度。
- getBoundingClientRect() 返回的是一个 DOMRect 对象,包括元素的位置和尺寸信息,可以通过 width 属性获取元素的宽度。
const element = document.getElementById('myElement');
// 获取元素实际的宽度
const offsetWidth = element.offsetWidth;
// 获取元素实际的高度
const offsetHeight = element.offsetHeight;
// 元素的实际距离左边界的距离
const offsetLeft = element.offsetLeft;
// 元素的实际距离上边界的距离
const offsetTop = element.offsetTop;
const clientHeight = element.clientHeight;
const clientWidth = element.clientWidth;
const scrollHeight = element.scrollHeight;
const scrollWidth = element.scrollWidth;
总结
DOM是Web开发中不可或缺的一部分,它提供了一种方便的方式来访问和操作HTML和XML文档。
理解 DOM 的结构和 API ,并且注意DOM的优化,夯实学习基础,有助于开发高效、响应式和可维护的Web应用程序。
特别是对 DOM 元素的宽高获取总是常常忘记😂,如果你也有这方面的困扰就赶紧收藏起来吧!!!
如果还有需要补充的知识点或者是常用 api 可以在评论区滴滴我啊,我会持续更新的 🎈!