MutationObserver实例中mutation.type为childList时addedNodes节点的筛选方法。

2025-09-21 17:21:49 132 分享链接 开发笔记 MutationObserver

在遍历addedNodes节点的过程中 我怎么筛选出指定的节点?

在遍历 addedNodes 时筛选指定节点,核心是通过 节点的属性或特征 进行条件判断(如标签名、类名、ID、属性等)。以下是常见的筛选场景和实现方法:

核心思路

  1. 先通过 node.nodeType === 1 确保只处理 元素节点(排除文本节点、注释节点等)。
  2. 根据需求,通过节点的属性(tagNameclassNameidattributes 等)设置筛选条件。

常见筛选场景示例

1. 按标签名筛选(如只保留 <div> 节点)

const addedNodes = Array.from(mutation.addedNodes);

addedNodes.forEach(node => {
  // 先判断是元素节点,再筛选标签名(tagName 是大写的,如 "DIV"、"P")
  if (node.nodeType === 1 && node.tagName === 'DIV') {
    console.log('筛选出的 DIV 节点:', node);
    // 对符合条件的节点进行操作
  }
});

2. 按类名筛选(如只保留含 active 类的节点)

addedNodes.forEach(node => {
  // 元素节点 + 包含指定类名
  if (node.nodeType === 1 && node.classList.contains('active')) {
    console.log('含 active 类的节点:', node);
  }
});

3. 按 ID 筛选(如只保留 ID 为 target 的节点)

addedNodes.forEach(node => {
  // 元素节点 + ID 匹配
  if (node.nodeType === 1 && node.id === 'target') {
    console.log('ID 为 target 的节点:', node);
  }
});

4. 按属性筛选(如只保留含 data-type="link" 属性的节点)

addedNodes.forEach(node => {
  // 元素节点 + 存在指定属性且值匹配
  if (node.nodeType === 1 && node.hasAttribute('data-type') && node.getAttribute('data-type') === 'link') {
    console.log('含 data-type="link" 的节点:', node);
  }
});

5. 按子节点特征筛选(如包含 <span> 子节点的节点)

addedNodes.forEach(node => {
  if (node.nodeType === 1) {
    // 查找是否有 <span> 子节点(使用 querySelector)
    const hasSpanChild = node.querySelector('span') !== null;
    if (hasSpanChild) {
      console.log('包含 span 子节点的节点:', node);
    }
  }
});

6. 多条件组合筛选(如 <a> 标签且含 external 类)

addedNodes.forEach(node => {
  if (
    node.nodeType === 1 && 
    node.tagName === 'A' &&  // 是 <a> 标签
    node.classList.contains('external')  // 含 external 类
  ) {
    console.log('符合条件的链接节点:', node);
  }
});

7. 直接通过 CSS 选择器 判断节点是否匹配

addedNodes.forEach(node => {
  // 先确保是元素节点(避免非元素节点调用 matches 报错)
  if (node.nodeType === 1 && node.matches('div')) {
    console.log('匹配的 div 节点:', node);
  }
});

进阶:先筛选再遍历(更简洁)

如果想先筛选出所有符合条件的节点,再统一处理,可以用 filter 方法:

const addedNodes = Array.from(mutation.addedNodes);

// 先筛选出所有 <p> 标签且含 class="content" 的节点
const filteredNodes = addedNodes.filter(node => {
  return node.nodeType === 1 && 
         node.tagName === 'P' && 
         node.classList.contains('content');
});

// 遍历筛选后的节点
filteredNodes.forEach(node => {
  console.log('筛选后的节点:', node);
  // 统一处理逻辑
});

关键总结

  • 筛选的核心是利用节点的 属性和方法tagNameclassListidhasAttribute 等)。
  • 始终先通过 node.nodeType === 1 过滤非元素节点,避免处理文本/注释节点导致的错误。
  • 根据实际需求组合条件,灵活使用 querySelector 等 DOM 方法简化判断。

根据你的具体场景(比如要筛选特定组件、特定属性的节点),只需调整条件即可。

详细介绍node.matchesCSS 选择器

你说得对!node.matches(selector) 是一个非常实用的方法,它可以直接通过 CSS 选择器 判断节点是否匹配指定规则,相比手动判断属性更加简洁高效。尤其适合在遍历 addedNodes 时筛选节点。

node.matches() 基本用法

  • 语法:node.matches(cssSelector)
  • 作用:判断当前节点是否匹配指定的 CSS 选择器,返回 truefalse
  • 优势:直接使用 CSS 选择器语法,无需手动拼接条件,代码更简洁。

在遍历中筛选指定节点的示例

1. 筛选特定标签(如 <div>

addedNodes.forEach(node => {
  // 先确保是元素节点(避免非元素节点调用 matches 报错)
  if (node.nodeType === 1 && node.matches('div')) {
    console.log('匹配的 div 节点:', node);
  }
});

2. 筛选含指定类名的节点(如 .active

addedNodes.forEach(node => {
  if (node.nodeType === 1 && node.matches('.active')) {
    console.log('含 active 类的节点:', node);
  }
});

3. 筛选指定 ID 的节点(如 #target

addedNodes.forEach(node => {
  if (node.nodeType === 1 && node.matches('#target')) {
    console.log('ID 为 target 的节点:', node);
  }
});

4. 筛选带特定属性的节点(如 [data-type="link"]

addedNodes.forEach(node => {
  if (node.nodeType === 1 && node.matches('[data-type="link"]')) {
    console.log('含 data-type="link" 属性的节点:', node);
  }
});

5. 复杂组合筛选(如 <a> 标签且含 .external 类且有 target 属性)

addedNodes.forEach(node => {
  // 用 CSS 选择器直接组合条件,非常简洁
  if (node.nodeType === 1 && node.matches('a.external[target]')) {
    console.log('符合条件的链接节点:', node);
  }
});

6. 筛选后代包含特定元素的节点(如包含 <span> 子节点的 <div>

addedNodes.forEach(node => {
  if (node.nodeType === 1 && node.matches('div:has(span)')) {
    // :has() 是 CSS 伪类,用于判断是否包含指定后代(现代浏览器支持)
    console.log('包含 span 子节点的 div:', node);
  }
});

进阶:结合 filter 批量筛选

如果需要先筛选出所有符合条件的节点再统一处理,可以配合 filter 使用:

// 筛选所有 <p> 标签且类名为 content 的节点
const filteredNodes = addedNodes.filter(node => {
  return node.nodeType === 1 && node.matches('p.content');
});

// 遍历筛选结果
filteredNodes.forEach(node => {
  console.log('筛选后的节点:', node);
  // 处理逻辑...
});

注意事项

  1. 节点类型判断:必须先通过 node.nodeType === 1 确保是元素节点,否则非元素节点(如文本节点)调用 matches() 会报错。
  2. 选择器兼容性matches() 支持大部分 CSS 选择器,但某些高级伪类(如 :has())在旧浏览器中可能不支持,需注意兼容性。
  3. 性能优势:相比手动判断多个属性,matches() 由浏览器原生实现,性能更优,且代码更易读。

使用 node.matches() 确实是筛选节点的最佳实践之一,尤其适合需要复杂条件筛选的场景,推荐优先使用!

MutationObserver实例中mutation.type为childList时addedNodes节点的筛选方法。