首选 document.querySelectorAll,因其返回静态 NodeList、支持任意 CSS 选择器、兼容性好且不进入 iframe/shadowRoot 外的子上下文;getElementsByTagName 仅查主文档树、返回实时集合、易出错。

document.querySelectorAll 是首选,不是 getElementsByTagName
直接用 document.getElementsByTagName 统计会漏掉嵌套在 iframe 或 shadowRoot 里的元素,而且它返回的是实时集合(live collection),在遍历中修改 DOM 容易出错。现代统计应统一走 document.querySelectorAll ——它返回静态 NodeList,支持任意 CSS 选择器,兼容性好,且不会因 DOM 变动意外改变长度。
常见错误现象:document.getElementsByTagName('div').length 在编辑器内容位于 contenteditable 区域内时,结果为 0,因为该方法只查主文档树,不自动进入子上下文。
- 若目标在 iframe 内:先取
iframe.contentDocument,再调用querySelectorAll - 若目标在 shadow DOM 中:用
host.shadowRoot.querySelectorAll('button') - 避免用
getElementsByClassName或getElementsByTagName做筛选,它们不支持复合条件(如[data-type="price"])
统计前必须确认作用域和内容归属
很多富文本编辑器(如 Quill、TinyMCE)把用户输入内容封装在独立容器里,比如 div[contenteditable="true"] 或 iframe 的 body。此时直接在主页面执行查询,等于在“空房间”里数家具——数量永远是 0。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 先定位编辑器根节点:
const editor = document.querySelector('#editor') - 再判断其类型:
if (editor.tagName === 'IFRAME') { editor.contentDocument.querySelectorAll(...) } - 如果是
contenteditable普通 div,直接在其上调用:editor.querySelectorAll('p'),而非document.querySelectorAll - 注意排除非用户内容:加过滤条件,如
:not([data-placeholder="true"])或:not(.ql-blank)
数字提取要防 NaN,文本清洗不能只靠 replace
如果目标是统计含数字的文本(如价格、销量),别直接 parseInt(el.textContent)。HTML 文本常带单位、逗号、空格甚至 Unicode 空格(\u200b),parseInt 遇到第一个非数字字符就停,parseFloat 同样不可靠。
推荐做法:
- 用正则提取完整数字片段:
el.textContent.match(/-?\d+\.?\d*/)?.[0](保留负号和小数点) - 转数值后校验:
const n = Number(matched); if (!isNaN(n) && isFinite(n)) sum += n - 优先读
data-*属性:Number(el.dataset.value),比解析文本稳定得多
去重统计要用 Set,别手写 indexOf 循环
统计唯一值(如表格某列姓名、标签类型)时,用 Array.from(...).filter() + indexOf 不仅慢,还容易漏空字符串或全空白项。
正确姿势:
- 提取并清洗:
const values = Array.from(document.querySelectorAll('td:nth-child(2)'), el => el.textContent.trim()) - 去重计数:
const uniqueCount = new Set(values.filter(v => v)).size - 注意边界:空字符串
''、仅空格的字符串经trim()后为'',会被filter(v => v)过滤掉,符合多数业务逻辑
Set 是浏览器原生支持的结构,现代项目无需 polyfill;手动模拟去重既冗余又易错,尤其当数据量超过几百项时,性能差距明显。



















