使用queryselectorall,jquery,getelementsbyid,getelementsbyclassname从dom中删除元素

时间:2014-10-31 00:55:43

标签: javascript

我正在为一个库创建一个函数,该函数接受一个元素对象并将其从DOM中删除。我有这个工作正常,但想知道是否有办法做一个for循环?我发现NodeListsHTMLCollections不能使用相同的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));

2 个答案:

答案 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)

由于以下原因,我建议使用更强大的实现:

  1. 如果它是传入的jQuery对象,那么你应该调用jQuery .remove(),因为如果不让jQuery删除jQuery操作的jQuery操作,jQuery可能会泄漏数据和事件监听器的内存.data().on()已与。

  2. 一起使用
  3. 仅仅执行if (elem.length)是不够的,因为它仍然可以是nodeList.length 0的数组。我将其更改为测试以查看该属性是否确实存在。仅供参考,如果你想要一个更强大的测试来看看它是否是一个真正的单个DOM节点,那么here有一个强大的功能,虽然我不确定这里是否需要。

  4. 为了防止动态nodeList从你或者孩子和父母一起更换到列表中(你不想在子节点之前删除父节点),最好从后面迭代nodeList前面(你不需要复制)。

  5. 如果这只是一个正常的DOM元素数组,这些元素不一定是文档顺序,并且列表中有父/子元素,乱序或任何人传递给你一个包含任何旧DOM元素的数组它,您最终可能会在.removeChild()操作上获得异常,因此最好只捕获可能发生的任何异常,以便操作始终可以在整个列表中完成,即使在该列表中存在错误元素列表

  6. 您的代码没有一致的返回值。它有一条路没有返回任何东西。我将其更改为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节点,你就没有它)。

  7. 推荐代码:

    {{1}}