自定义getElementsByClassName函数中如何正确访问并遍历document.body?
自定义getElementsByClassName函数:document.body返回null及实现疑问
我想实现一个自定义的getElementsByClassName函数,但函数里调用document.body总是返回null。我知道递归部分还需要完善,但先想搞清楚怎么在函数里正确访问document.body及其childNodes,或者我的实现思路是不是有问题?
原代码如下:
var getElementsByClassName = function() { var bod = document.body; for (var i = 0; i < bod.childNodes.length; i++) { var thisNode = bod.childNodes[i]; var classTest = bod.childNodes[i].className; if (classTest === classname) { } //recursion here if (thisNode.childNodes.length > 0) { getElementsByClassName(); } } };
问题分析与解决
1. document.body返回null的核心原因
这是因为你的脚本在DOM还未完全加载时就执行了。浏览器解析HTML是从上到下的,如果你的脚本放在<head>里,此时<body>标签还没被解析,document.body自然就是null。
解决方法:
- 把脚本标签放在HTML的
</body>结束标签之前,确保DOM已经加载完成 - 或者用DOM加载完成的事件监听包裹代码:
document.addEventListener('DOMContentLoaded', function() { // 在这里调用你的自定义getElementsByClassName函数 });
2. 原函数的其他逻辑问题
除了DOM加载时机,你的函数还有几个关键问题:
- 没有接收目标类名参数:函数定义时没有参数,
classname变量未定义,根本无法判断节点类名是否匹配 - 递归逻辑错误:每次递归都重新获取
document.body,应该把当前遍历的节点作为参数传递给递归函数,否则会重复遍历整个文档根节点 - 未收集结果:没有数组来存储符合条件的节点,最后也没有返回结果
- 未过滤非元素节点:
childNodes会包含文本节点、注释节点(nodeType !== 1),这些节点没有className属性,直接访问会报错
3. 修正后的示例代码
以下是修复后的基础版本,解决了上述问题:
function getElementsByClassName(targetClass) { // 存储结果的数组 const result = []; // 递归遍历节点的函数 function traverse(node) { // 只处理元素节点 if (node.nodeType === 1) { // 判断当前节点是否包含目标类名 if (node.classList.contains(targetClass)) { result.push(node); } // 遍历子节点,递归处理 for (let i = 0; i < node.childNodes.length; i++) { traverse(node.childNodes[i]); } } } // 从document.body开始遍历 if (document.body) { traverse(document.body); } return result; } // 使用示例(确保在DOM加载完成后调用) document.addEventListener('DOMContentLoaded', function() { const elements = getElementsByClassName('test-class'); console.log(elements); });
内容的提问来源于stack exchange,提问作者maximosis
相关产品推荐
相关产品推荐

