JS 中操作 DOM 节点


DOM 概念


将 HTML 文档中的标签、标签属性、标签文本转换为一个个对象, 并按照标签之间的关系, 将这些对象以树形结构的形式保存在内存中, 然后可以用操作对象的方式对实际元素进行修改。

DOM树:

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 属性对其类型进行区分

常见的节点类型有:

节点类型nodeTypenodeNamenodeValue
元素节点1元素名null/undefined
属性节点2属性名属性值
文字节点3text文本内容
注释节点8comment注释内容

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>

添加节点


  1. document.createElement,创建元素对象(只是创建元素对象, 并不会添加到页面)
  2. node.appendChild(element),页面添加元素 - 末尾添加
  3. node.insertBefore(element, targetElement),页面添加元素 - 添加位置取决于第二个参数
  4. 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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值