JavaScript | 节点操作

在JavaScript中,DOM节点操作是非常常见的基础交互功能,这是构建网页交互层的基础。本文总结了有关于DOM节点操作常见的操作,供大家方便查阅。

什么是 DOM?

文档对象模型 (DOM) 是 HTML 和 XML 文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式可以使从程序中对该结构进行访问,从而改变文档的结构,样式和内容。DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。简言之,它会将 web 页面和脚本或程序语言连接起来。------MDN------什么是 DOM?

白话文:DOM是浏览器提供的用来操作网页内容的功能

DOM树

将HTML文档以树状结构直观的表现出来,称之为文档树或 DOM树

作用:文档树直观的体现了标签与标签之间的关系

DOM对象

DOM对象:浏览器根据html标签自动生成的js对象

  • 所有的标签属性都可以在这个对象上面找到
  • 修改这个对象的属性会自动映射到对象标签上

DOM核心思想:

  • 把网页当作对象来处理

document对象:

  • DOM提供的对象
  • 其提供的属性和方法都是用于操作网页内容的
  • 网页所有内容都在document里

DOM节点

DOM树中的每个内容都称为节点

节点类型:

  • 元素节点 (重点)
    • 所有的标签比如body、div
    • html为根节点
  • 属性节点
    • 所有的属性比如href属性
  • 文本节点
    • 所有的文本
  • 其他

获取DOM元素

1 匹配满足条件的第一个元素

语法:

document.querySelector('css选择器')

参数:

包含一个或者多个有效的css选择器

返回:

返回匹配的第一个html元素

javascript 复制代码
// 获取元素 querySelector 匹配第一个对应的元素对象
// let div = document.querySelector('div');
let div = document.querySelector('.three');
console.log(div);

let li = document.querySelector('ul li:last-child');
console.log(li.innerHTML);

2 匹配满足条件的多个元素

语法:

document.querySelectorAll('css选择器')

参数:

包含一个或者多个有效的css选择器

返回:

返回匹配的Nodelist的集合 (注:NodeList是一个伪数组,要想得到里面的元素可以通过for循环的方式获得)

注意:这里如果即便只有一个元素满足条件,返回的也是NodeList

javascript 复制代码
let lis = document.querySelectorAll('ul li');
console.log(lis);
// 通过遍历的方式获取里面的dom对象
for (let i = 0; i < lis.length; i++) {
    log(lis[i]);
}

3 根据id获取一个元素

document.getElementById('mark')

4 根据标签获取一个元素

document.getElementByTagName('div')

5 根据类名获取元素 获取页面所有类名为 xxx 的元素

document.getElemntByClassName('xxx')

查找节点

查找父节点

  • 通过parentNode属性获取
  • 返回最近的父节点,如果不存在则返回null
  • 语法:document.querySelector('#patty').parentNode;

查找子节点

  1. childNodes属性(不推荐使用)
    • 获得所有的子节点,包括文本节点(空格、换行)、注释节点等
  2. children属性
    • 获取所有的子元素节点

    • 返回值为一个HTMLCollection,这是一个伪数组。

      html 复制代码
      <ul>
        <li>1</li>
        <!-- 注释节点 -->
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
      </ul>
      <script>
        let ul = document.querySelector('ul');
        console.log(ul.childNodes); // NodeList(13)
        console.log(ul.children); // HTMLCollection(5) [li, li, li, li, li]
      </script>

查找兄弟节点

  1. 获取下一个兄弟节点
    • nextElementSibling属性
  2. 获取上一个兄弟节点
    • previousElementSibling属性
  3. 补充nextSibling与previousSibling
    • 会将空格或者换行当做节点处理

      html 复制代码
      <div id="previous">
      卧槽不是吧
      </div>
      <ul>
        <li>1</li>
        <!-- 注释节点 -->
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
      </ul>
      <div id="nest">
      明华大鼬
      </div>
      <script>
        let ul = document.querySelector('ul');
        console.log(ul.previousElementSibling); // div#previous
        console.log(ul.nextElementSibling); // div#nest
        // nextSibling,previousSibling都会将空格或者换行当做节点处理
        console.log(ul.previousSibling); // text
        console.log(ul.previousSibling.previousSibling); // div#previous
        console.log(ul.nextSibling); // text
        console.log(ul.nextSibling.nextSibling); // div#next
      </script>

查找第一个节点|最后一个节点

  1. 查找第一个节点
    • 属性firstElementChild
    • 如果子元素不存在则返回null
  2. 查找最后一个节点
    • 属性lastElementChild
    • 如果子元素不存在则返回null
  3. 补充firstChild与lastChild
    • 会将空格或者换行当做节点处理

      html 复制代码
      firstElementChild<ul>
        114514
        <li>1</li>
        <!-- 注释节点 -->
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        1919810
      </ul>
      <script>
        let ul = document.querySelector('ul');
        // 1
        console.log(ul.firstElementChild.textContent);
        // 5
        console.log(ul.lastElementChild.textContent);
        // 114514
        console.log(ul.firstChild);
        // 1919810
        console.log(ul.lastChild);
      </script>

小结

关系 考虑所有节点 考虑元素节点
子节点 childNodes children
父节点 parentNode parentNode
第一个子节点 firstChild firstElementChild
最后一个子节点 lastChild lastElementChild
前一个兄弟节点 previousSibling previousElementSibling
后一个兄弟节点 nextSibling nextElementSibling

添加节点

创建节点

创建方法:

document.createElement('标签名')

通过createElement方法创建的元素不属于document文档,只是创建了个新的元素节点 ,还需要通过追加节点的方式将其添加到页面上。

了解:还可以通过createTextNode的方式创建文本节点。

追加节点

  1. appendChild方法

    • 插入到父元素的最后一个子元素

    • 语法

      javascript 复制代码
      // 追加到这个父元素的后面
      parentNode.appendChild(child);
      // parentNode - 父元素
      // child 要追加的节点
  2. insertBefore方法

    • 插入到父元素中某个元素的前面

    • 语法

      javascript 复制代码
      // 插入到某个子元素的前面
      parentNode.insertBefore(newNode, referenceNode)
      // parentNode 父节点
      // newNode 要追加的节点
      // referenceNode 在这元素的前面

案例:

html 复制代码
<ul>
</ul>
<script>
    let data = [
      {
        id:1,
        name: 'David'
      },
      {
        id:2,
        name: 'Lucy'
      },
      {
        id:3,
        name: 'Blue'
      },
      {
        id:4,
        name: 'Red'
      },
      {
        id:5,
        name: 'Dipper'
      },
    ]
    let ul = document.querySelector('ul');
    data.forEach((item,index)=>{
      let newli = document.createElement('li');
      newli.innerHTML = `
        id:${item.id}<span style="margin-left: 15px"></span>name:${item.name}
      `;
      ul.appendChild(newli);
    })
    let zeroli = document.createElement('li');
    zeroli.innerHTML = `
        id:0<span style="margin-left: 15px"></span>name:Zero
      `;
    ul.insertBefore(zeroli, ul.firstElementChild);
</script>

效果图:

  1. 补充:insertAdjacentElement方法

    insertAdjacentElement() 方法将一个给定的元素节点插入到相对于被调用的元素的给定的一个位置。

    语法:element.insertAdjacentElement(position, element);

    参数:

    1. position:表示相对于该元素的位置;必须是以下字符串之一:
      1. beforebegin:在该元素本身的前面.
      2. afterbegin:只在该元素当中, 在该元素第一个子孩子前面.
      3. beforeend:只在该元素当中, 在该元素最后一个子孩子后面.
      4. afterend: 在该元素本身的后面.
    2. 要追加到树中的元素.

    所以对于第1点和第2点中提到的appendChild方法和insertBefore方法也可以通过insertAdjacentElement方法代替,具体如下

    • appendChild->parentNode.insertAdjacentElement('beforeend',child)
    • insertBefore->Node.insertAdjacentElement('beforebegin',child)

    所以通过上面的思路可以重写刚才的案例,代码如下:

    html 复制代码
    <ul>
    </ul>
    <script>
      let data = [
        {
          id:1,
          name: 'David'
        },
        {
          id:2,
          name: 'Lucy'
        },
        {
          id:3,
          name: 'Blue'
        },
        {
          id:4,
          name: 'Red'
        },
        {
          id:5,
          name: 'Dipper'
        },
      ]
      let ul = document.querySelector('ul');
      data.forEach((item,index)=>{
        let newli = document.createElement('li');
        newli.innerHTML = `
          id:${item.id}<span style="margin-left: 15px"></span>name:${item.name}
        `;
        // ul.appendChild(newli);
        ul.insertAdjacentElement('beforeend',newli);
      })
      let zeroli = document.createElement('li');
      zeroli.innerHTML = `
          id:0<span style="margin-left: 15px"></span>name:Zero
        `;
      //  ul.insertBefore(zeroli, ul.firstElementChild);
      ul.children[0].insertAdjacentElement('beforebegin',zeroli);
      // ul.children[0].insertAdjacentHTML('beforebegin',`<li>id:0<span style="margin-left: 15px"></span>name:Zero</li>`);
    </script>

删除节点

removeChild()方法方法从DOM中删除一个子节点。

使用:

let oldNode = Node.removeChild(child)

  • child 是要移除的那个子节点.
  • Node 是child的父节点.
  • oldChild保存对删除的子节点的引用. oldChild === child.

案例:

需求进入页面的时候删除一个节点,2s之后将此节点重新添加回页面中

html 复制代码
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>
<script>
  let ul = document.querySelector('ul');
  let oldChild = ul.removeChild(ul.firstElementChild);
  // 2s 之后重新将删掉的元素添加会ul标签中
  setTimeout(()=>{
    ul.insertAdjacentElement('afterbegin', oldChild);
  }, 2000);
</script>

注意:

  • 如果此时不存在父子关系则会删除失败
  • 与隐藏节点不同,删除节点是直接从文档流中删掉对应的dom元素

克隆节点

cloneNode()方法返回调用该方法的节点的一个副本

使用:var dupNode = node.cloneNode(deep);

参数deep:

  1. 布尔值为true,表示克隆的时候会包含后代节点一起克隆
  2. 如果为false,表示克隆的时候不包含后代节点一起克隆
  3. 默认情况下为false

案例:

要求2s之后复制一个一模一样的ul标签,追加为现在ul的兄弟节点,要求深度克隆

html 复制代码
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>
<script>
  let ul = document.querySelector('ul');
  let oldChild = ul.removeChild(ul.firstElementChild);
  // 2s之后复制一个一模一样的ul标签,追加为现在ul的兄弟节点,要求深度克隆
  setTimeout(()=>{
    let copyUl = ul.cloneNode(true);
    ul.parentNode.appendChild(copyUl);
  }, 2000);
</script>

判断节点是否存在

  • 单个元素节点,判定是否为空

  • 多个元素集合比如NodeList或者HTMLCollection判断长度是否大于0即可

    javascript 复制代码
    let span = document.querySelector('span');
    console.log(span !== null);
    let divs = document.querySelectorAll('div');
    console.log(divs.length>0);

获取/修改DOM元素的内容

获取/修改节点内的内容

  1. innerText属性

    • 将文本的内容添加到标签里面
    • 文本里包含的标签内容不会被解析
  2. innerHTML属性

    • 将文本的内容添加到标签里面

    • 文本里包含的标签内容会被解析

    • 效果与代码如下所示

    html 复制代码
    <ul>
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
      <li>5</li>
    </ul>
    <ol>
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
      <li>5</li>
    </ol>
    <script>
      let ul = document.querySelector('ul');
      let ol = document.querySelector('ol');
      // 1 2 3 4 5
      console.log(ul.innerText); 
      //<li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li>
      console.log(ul.innerHTML); 
      // 1.
      ul.innerText = '<li><span>1<span></li>';
      ol.innerHTML = '<li><span>1<span></li>';
    </script>

获取/修改包含节点本身的内容

通过outerHTML可以获取/设置包含节点本身的内容

html 复制代码
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>
<script>
  let ul = document.querySelector('ul');
  let ol = document.querySelector('ol');
  //<ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> </ul>
  console.log(ul.outerHTML); 
  ul.outerHTML = `<ul><li>114514</li></ul>`;
</script>

获取/修改DOM元素属性

判断是否设置属性

javascript 复制代码
document.getElementById('pattyzzh').hasAttribute('class');

获取属性

javascript 复制代码
document.getElementById('pattyzzh').getAttribute('class');

删除属性

javascript 复制代码
document.getElementById('pattyzzh').removeAttribute('class');

设置属性

  1. 通用写法

    javascript 复制代码
    document.getElementById('pattyzzh').setAttribute('class','patty');
  2. 设置元素常用属性

  • 比如通过src更换图片

  • 最常见的属性包括:href、title、src等

  • 语法:对象.属性 = 值

    javascript 复制代码
    // 1.获取图片素材
    let pic = document.querySelector('img');
    // 2.设置图片的src
    pic.src = `./img/1.png`;
  1. 设置元素样式属性

    • 语法:对象.style.样式属性 = 值

    • 修改样式通过style属性引出

    • 如果属性有-连接符号,需要转为小驼峰命名法

    • 赋值的时候不要忘了加css单位

      javascript 复制代码
      // 1. 获取元素
      let div = document.querySelector('div');
      // 2.改变样式
      setTimeout(()=>{
          // 行内样式
          div.style.backgroundColor = 'hotpink';
          div.style.width = '400px';
          div.style.marginTop = '100px';
      }, 1000);
  2. 通过className(类名)操作css

    • 语法:对象.className = '类名'

    • class是关键字,所以使用className代替

    • className是使用新值替换旧值,如果需要添加一个类,需要保留之前的类名

      html 复制代码
      <style>
          div {
              width: 300px;
              height: 300px;
              background-color: pink;
          }
      
          .active {
              width: 300px;
              height: 300px;
              background-color: hotpink;
              margin-left: 100px;
          }
      </style>
      <div class="one"></div>
      <script>
          // 1. 获取元素
          let div = document.querySelector('div');
          // 2.改变样式
          div.className = 'one active';
      </script>
  3. 通过classList操作类控制css

    • 为了解决className容易覆盖一起的类目,所以可以通过classList方式追加和删除类名

    • 语法:

      javascript 复制代码
      // 追加一个类
      元素.classList.add('类名');
      // 删除一个类
      元素.classList.remove('类名');
      // 切换一个类
      元素.classList.toggle('类名');
      javascript 复制代码
      // 1. 获取元素
      let div = document.querySelector('div');
      // 2.改变样式 追加
      // div.classList.add('active');
      // 3.移除 类
      // div.classList.remove('active')
      // 4.切换 类 如果所在的类有 则去掉 ,否则加上
      div.classList.toggle('one');

参考文献

相关推荐
卸任6 小时前
Vibe coding工具使用心得
前端·ai编程
brien97 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance7 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M7 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写7 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李7 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易7 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
清晨Coding8 小时前
删了 Cookie 还能自动登录?Google系网站登录态自动恢复的原理分析
javascript
风骏时光牛马8 小时前
前沿视界
前端
kyriewen8 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员