我正在为一个库创建一个函数,该函数接受一个元素对象并将其从DOM中删除。我有这个工作正常,但想知道是否有办法做一个for
循环?我发现NodeLists
和HTMLCollections
不能使用相同的for循环,因此我构建了一个数组,然后删除了具有相同循环的元素。
_remove = function(elem) {
if(!elem) { return false; }
// getElementById
if(!elem.length) {
if(elem.parentNode) {
elem.parentNode.removeChild(elem);
}
// querySelectorAll, jquery, getElementsByClassName, getElementsByTagName
} else {
var elems = [];
for(var j = 0; j<elem.length; j++) {
if(elem[j]) {
elems.push(elem[j]);
}
}
for(var i=0; i<elems.length; i++) {
if(elems[i].parentNode) {
elems[i].parentNode.removeChild(elems[i]);
}
}
return false;
}
}
呼叫:
_remove(document.getElementById('someId'));
_remove(document.getElementsByClassName('someClass'));
_remove(document.getElementsByTagName('tag'));
_remove($('#someId));
_remove($('.someClass));
_remove(document.querySelectorAll('someID or Class or Tag));
答案 0 :(得分:5)
其中一些函数返回 live NodeList,这意味着当您更改DOM时,集合会立即更改以反映这一点。这就是普通for
循环不起作用的原因:当您删除elem[0]
时,集合中的所有其他条目都会向下移动。然后,当您递增索引时,将跳过新的elem[0]
。
解决此问题的最简单方法是从高端向下循环,而不是从0向上循环。
for (var j = elem.length-1; j >= 0; j--) {
if (elem[j].parentNode) {
elem[j].parentNode.removeChild(elem[j]);
}
}
答案 1 :(得分:2)
由于以下原因,我建议使用更强大的实现:
如果它是传入的jQuery对象,那么你应该调用jQuery .remove()
,因为如果不让jQuery删除jQuery操作的jQuery操作,jQuery可能会泄漏数据和事件监听器的内存.data()
或.on()
已与。
仅仅执行if (elem.length)
是不够的,因为它仍然可以是nodeList
或.length
0
的数组。我将其更改为测试以查看该属性是否确实存在。仅供参考,如果你想要一个更强大的测试来看看它是否是一个真正的单个DOM节点,那么here有一个强大的功能,虽然我不确定这里是否需要。
为了防止动态nodeList从你或者孩子和父母一起更换到列表中(你不想在子节点之前删除父节点),最好从后面迭代nodeList前面(你不需要复制)。
如果这只是一个正常的DOM元素数组,这些元素不一定是文档顺序,并且列表中有父/子元素,乱序或任何人传递给你一个包含任何旧DOM元素的数组它,您最终可能会在.removeChild()
操作上获得异常,因此最好只捕获可能发生的任何异常,以便操作始终可以在整个列表中完成,即使在该列表中存在错误元素列表
您的代码没有一致的返回值。它有一条路没有返回任何东西。我将其更改为false
如果elem
无效,则返回true
,如果已处理则// _remove(elem) - remove one or more DOM nodes from their DOM hierarchy
// elem can be an Array of DOM nodes or a pseudo-array like a nodeList
// or elem can be a single DOM element
function _remove(elem) {
if (!elem) {
return false;
} else if (typeof elem.jquery === "string" && typeof elem.remove === "function") {
// if a jQuery object, it should be removed with jQuery
// so jQuery data and event listener stuff will get cleaned up
// there are more comprehensive ways to check for a jQuery object,
// but those are probably not needed here
elem.remove();
} else if (elem.nodeType) {
// single DOM node
// could also do more comprehensive test to see if it's really a DOM node,
// but probably not needed
if (elem.parentNode) {
elem.parentNode.removeChild(elem);
}
} else if (typeof elem.length === "number") {
// array or pseudo-array here
// querySelectorAll, getElementsByClassName, getElementsByTagName or
// an array of DOM elements assembled by any other code
// iterate backwards so if it is a dynamic nodeList, then children will be
// be removed before parents and any nodeList changes will happen after our
// iteration point
for (var i = elem.length - 1; i >= 0; i--) {
// catch errors in case anything has already been deleted
// from a prior parent delete so we don't abort early
try {
elem[i].parentNode.removeChild(elem[i]);
} catch(e) { }
}
} else {
// don't know what was passed here - not something we were expecting
return false;
}
return true;
}
。显然你可以根据需要修改它,但是如果你要有一个有意义的返回值,你应该有一个所有代码路径的返回值(如果它是一个DOM节点,你就没有它)。
推荐代码:
{{1}}