文章目录
DOM 概念
将 HTML 文档中的标签、标签属性、标签文本转换为一个个对象, 并按照标签之间的关系, 将这些对象以树形结构的形式保存在内存中, 然后可以用操作对象的方式对实际元素进行修改。
DOM树:
DOM 操作
条件查找
根据条件进行查找 如, 想查找某个类型的元素、查找指定 ID 的元素、查找使用了指定样式的元素等,条件查找时,返回的都是HTMLElement 对象( Node 对象的子类 )
1. 根据 id 属性查找元素
<div id='container'></div>
<script>
document.getElementById('container')
</script>
2. 根据元素类型查找元素
<div></div>
<div></div>
<script>
let elementArray = document.getElementsByTagName('div')
for (let i = 0; i < elementArray.length; i++) {
elementArray[i].innerText = `我是第${i + 1}个div`
}
</script>
3. 根据 class 属性查找元素
<style>
.font-red {
color: red;
}
</style>
<div class="font-red"></div>
<div class="font-red"></div>
<script>
let elementArray = document.getElementsByClassName('font-red')
for (let i = 0; i < elementArray.length; i++) {
elementArray[i].innerText = `我是第${i + 1}
}
</script>
4. 根据选择器查找第一个命中的元素
<div></div>
<p class="font-red"></p>
<div class="font-red"></div>
<script>
// 使用标签选择器
console.dir(document.querySelector('div'))
// 使用类选择器
console.dir(document.querySelector('.font-red'))
// 使用更详细的类选择器
console.dir(document.querySelector('div.font-red'))
</script>
5. 根据选择器查找全部命中的元素
<div></div>
<div></div>
<script>
let elementArray = document.querySelectorAll('div')
for (let i = 0; i < elementArray.length; i++) {
elementArray[i].innerText = `我是第${i + 1}个div`
}
</script>
6. 查找页面根元素或Body元素
<script>
// 获取 body 元素
console.dir(document.body)
// 获取根元素
console.dir(document.documentElement)
// 不同浏览器或浏览器版本,在获取滚动条的滚动距离时,可能会有兼容问题
// 解决兼容问题
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop
</script>
爬树查找
按照树形结构中的关系进行查找, 如, 父节点、子节点、兄弟节点等,爬树查找时,返回的都是 Node 对象。
DOM 树的节点有不同的类型, Node 对象中由 nodeType 属性对其类型进行区分
常见的节点类型有:
节点类型 | nodeType | nodeName | nodeValue |
---|---|---|---|
元素节点 | 1 | 元素名 | null/undefined |
属性节点 | 2 | 属性名 | 属性值 |
文字节点 | 3 | text | 文本内容 |
注释节点 | 8 | comment | 注释内容 |
1. 查找父节点
<div id="grandpa">
<div id="parent">
<div id="inner"></div>
</div>
</div>
<script>
let innerDiv = document.querySelector('#inner')
console.log(innerDiv.parentNode)
</script>
2. 查找子节点 - 元素节点、注释节点、文本节点
<div id="outer">
文本<!-- 注释节点 -->
<div id="son">节点值
<div id="grandson"></div>
</div>
</div>
<script>
let innerDiv = document.querySelector('#outer')
let children = innerDiv.childNodes
console.log(`一共有${children.length}个子节点`)
for (let i = 0; i < children.length; i++) {
console.log(`第${i + 1}个节点, 节点名为:${children[i].nodeName}`)
console.log(`第${i + 1}个节点, 节点类型为:${children[i].nodeType}`)
console.log(`第${i + 1}个节点, 节点值为:${children[i].nodeValue}`)
}
/**
* 第一个节点: 是文本节点,既 <div id="outer"> 后的 换行符 + 空格 + 文本
* 第二个节点: 是注释节点,既 <!-- 注释节点 -->
* 第三个节点: 是文本节点,既 < !--注释节点 --> 后的 换行符 + 空格
* 第四个节点: 是元素节点,既 < div id = "son" > </div > 部分
* 第五个节点: 是文本节点,既 < div id = "son" > </div > 后的 换行符
*/
</script>
3. 查找子节点 - 元素节点
<div id="outer">
文本<!-- 注释节点 -->
<div id="son">
<div id="grandson"></div>
</div>
</div>
<script>
let innerDiv = document.querySelector('#outer')
// 只获取元素节点,既 <div id="son"> </div> 部分
let children = innerDiv.children
console.log(innerDiv.children.length) // 结果:1
for (let i = 0; i < children.length; i++) {
console.log(children[i])
}
</script>
4. 获取第一个和最后一个节点
<div id="outer">
<div id="son"></div>
<div id="daughter"></div>
</div>
<script>
let innerDiv = document.querySelector('#outer')
// 查找第一个和最后一个节点(可能是元素节点、文本节点、注释节点)
console.log(innerDiv.firstChild)
console.log(innerDiv.lastChild)
// 查找第一个和最后一个元素节点,有浏览器兼容问题
console.log(innerDiv.firstElementChild)
console.log(innerDiv.lastElementChild)
// 查找第一个和最后一个元素节点,最优方案
console.log(innerDiv.children[0])
console.log(innerDiv.children[innerDiv.children.length - 1])
</script>
5. 查找前一个兄弟节点
<div id="outer">
<div id="sibling"></div>
<div id="current"></div>
</div>
<script>
/*
* previousSibling - 查找前一个兄弟节点(文本类型、元素类型、注释类型)
* previousElementSibling - 查找前一个元素类型的兄弟节点
*/
let currentDiv = document.querySelector('#current')
console.log(currentDiv.previousSibling) // 结果: 文本类型节点,既 <div id="sibling"></div> 后的换行和空格
console.log(currentDiv.previousElementSibling) // 结果: 元素类型节点,既<div id="sibling"></div>
</script>
6. 查找后一个兄弟节点
<div id="outer">
<div id="current"></div>
<div id="sibling"></div>
</div>
<script>
/*
* nextSibling - 查找后一个兄弟节点(文本类型、元素类型、注释类型)
* nextElementSibling - 查找后一个元素类型的兄弟节点
*/
let currentDiv = document.querySelector('#current')
console.log(currentDiv.nextSibling) // 结果: 文本类型节点,既 <div id="current"></div> 后的换行和空格
console.log(currentDiv.nextElementSibling) // 结果: 元素类型节点,既<div id="sibling"></div>
</script>
添加节点
- document.createElement,创建元素对象(只是创建元素对象, 并不会添加到页面)
- node.appendChild(element),页面添加元素 - 末尾添加
- node.insertBefore(element, targetElement),页面添加元素 - 添加位置取决于第二个参数
- createElement 应与 appendChild 或 insertBefore 联合使用
insertBefore 的第二个参数传 null 则在节点末尾添加, 第二个参数传节点对象,则在节点对象前添加
<body>
<div id="container">
<h2 id="target">中间的元素</h2>
</div>
<script>
let target = document.getElementById('target')
let container = document.getElementById('container')
// 在 container 内 target 前,添加元素
let before = document.createElement('h2')
before.innerText = '添加到开头的元素'
container.insertBefore(before, target)
// 在 container 的末尾添加元素
let last = document.createElement('h2')
last.innerText = '添加到后面的元素'
container.appendChild(last)
</script>
</body>
移除节点
移除指定元素内的指定节点
<div id="container">
<h2 id="target">会被移除的元素</h2>
</div>
<script>
let target = document.getElementById('target')
let container = document.getElementById('container')
container.removeChild(target)
</script>
复制节点
浅拷贝:cloneNode() 函数的实参为 false 或 不传, 只拷贝节点本身, 哪怕下级是文本节点也不会拷贝
<div id="container">
<h2 id="target">这是内部节点</h2>
</div>
<script>
let container = document.querySelector('#container')
let target = document.querySelector('#target')
let copy = target.cloneNode()
// 不会拷贝文本节点, 所以要自己设置文字, 不然画面啥都不显示
copy.innerText = '这是复制出来的内部节点'
container.appendChild(copy)
</script>
深拷贝:cloneNode() 函数的实参为 true,拷贝节点本身和下级节点
<div id="container">
<h2 id="target">这是内部节点</h2>
</div>
<script>
let container = document.querySelector('#container')
let target = document.querySelector('#target')
let copy = target.cloneNode(true)
container.appendChild(copy)
</script>
操作元素值
value:用在表单元素中,设置和获取表单元素的值, 和表单元素中的的 value 属性对应
innerText:设置和获取元素标签对儿中的文字文本, 并会自动忽略文本的前后空格和换行符
innerHTML:设置和获取元素标签对儿中的内容(包括 html 标签),赋值时如果内容为 html 标签,页面则会自动识别成 html 元素
<!-- innerHtml -->
<div id="innerHTMLCase">
<h2> 这是 innerHTML 取值 </h2>
</div>
<!-- innerText -->
<div id="innerTextCase">
<h2> 这是 innerText 取值 </h2>
</div>
<!-- value -->
<input id="valueCase" type="text" value="这是文本框值">
<script>
/*
* innerHTML
*/
let innerHTMLCase = document.querySelector('#innerHTMLCase')
// 取值
console.log(innerHTMLCase.innerHTML) // 结果: \n <h2> 这是 innerHTML 取值 </h2>
// 赋值
innerHTMLCase.innerHTML = '<h2 id="target"> 这是 innerHTML 赋值 </h2>' // 画面看效果
/*
* innerText
*/
let innerTextCase = document.querySelector('#innerTextCase')
// 取值
console.log(innerTextCase.innerText) // 结果:这是 innerText 取值
// 赋值
innerTextCase.innerText = '<h2 id="target"> 这是 innerText 赋值 </h2>' // 画面看效果
/*
* value
*/
let valueCase = document.querySelector('#valueCase')
// 取值
console.log(valueCase.value) // 结果:这是文本框值
// 赋值
valueCase.value = '这是修改后的文本框值' // 画面看效果
</script>
操作元素属性
常用操作:
函数名 | 描述 |
---|---|
getAttribute( 属性名 ) | 获取元素属性 |
setAttribute( 属性名, 属性值 ) | 设置元素属性 |
removeAttribute( 属性名 ) | 删除元素属性 |
element.className | 设置和获取元素类名 |
element.属性名 | 设置和获取元素属性 |
① 属性操作配合自定义属性
<div id="defineProp" prop="自定义属性"></div>
<script>
let defineProp = document.querySelector('#defineProp')
console.log(defineProp.getAttribute('prop')) // 获取自定义属性值
defineProp.setAttribute('index', '1') // 设置自定义属性
defineProp.removeAttribute('prop') // 删除自定义属性
defineProp.style = 'width: 100px; height: 100px; border: 1px solid black' // 设置元素属性
</script>
② H5 规范了自定义属性要用 data- 开头, 然后统一从元素对象的 dataset 属性中获取, 获取时不用写 data-
<div id="singleton" data-singleton="自定义属性, 普通属性名"></div>
<div id="camelCase" data-camel-case="自定义属性, 驼峰属性名"></div>
<script>
// 普通属性名
let singleton = document.querySelector('#singleton')
console.log(singleton.dataset.singleton) // 方式一
console.log(singleton.dataset['singleton']) // 方式二
singleton.dataset.no = '1' // 通过 js 也可以为 html 元素设置自定义属性
// 驼峰属性名
let camelCase = document.querySelector('#camelCase')
console.log(camelCase.dataset.camelCase) // 方式一
console.log(camelCase.dataset['camelCase']) // 方式二
// 移除属性时, 不能省略 data-
camelCase.removeAttribute('data-camel-case')
</script>