【问题标题】:Remove all element without attribute删除所有没有属性的元素
【发布时间】:2014-03-07 06:01:25
【问题描述】:

我试图了解如何删除所有没有指定属性的子元素,例如:

这是 html:

<div class="container">
  <span></span>
  <div></div>
  <strong data-*></strong>
  <p></p>
  <div data-*></div>
</div>

我想要的是删除容器内的所有元素并且没有 data-* 属性。

数据-*

属性可以是data-anything(data-color、data-border等)。

我正在寻找仅限 JavaScript 的解决方案

【问题讨论】:

  • 如果你正在使用 jQuery,现在是时候说出来了吗?
  • 你能展示你真实的 HTML 吗?
  • 我没有在这个项目中使用 jQuery。
  • 如果您使用的是 jQuery,这将是解决方案:stackoverflow.com/questions/12199008/… 只是发布它以防有人在搜索中找到它。
  • 这是可能的,但它会非常慢。 (检查页面上的所有元素,将属性加载到数组中,在数组中搜索data-,如果没有匹配,最后删除元素)

标签: javascript html


【解决方案1】:

使用.filter().some().forEach() 应该可以解决问题。

var els = document.querySelectorAll(".container *");

[].filter.call(els, function(el) {
    return ![].some.call(el.attributes, function(attr) {
        return /^data/i.test(attr.name);
    });
}).forEach(function(el) {
    el.parentNode.removeChild(el);
});

您需要旧浏览器的补丁,但您可能已经知道了。


如果你像我一样,喜欢可重用的函数:

var els = document.querySelectorAll(".container *");

[].filter.call(els, els_with_no_data)
  .forEach(remove_nodes);

function remove_nodes(el) {
    el.parentNode.removeChild(el);
}

function has_data_attrs(attr) {
    return /^data/i.test(attr.name);
}

function els_with_no_data(el) {
    return ![].some.call(el.attributes, has_data_attrs)
}

然后使用 Array generics(在支持的浏览器中,否则 polyfiilled):

var els = document.querySelectorAll(".container *");

Array.filter(els, els_with_no_data)
     .forEach(remove_nodes);

function remove_nodes(el) {
    el.parentNode.removeChild(el);
}

function has_data_attrs(attr) {
    return /^data/i.test(attr.name);
}

function els_with_no_data(el) {
    return !Array.some(el.attributes, has_data_attrs)
}

【讨论】:

  • &gt;_&lt; 这正是我想写的。
  • 明白了!您需要反转集合。否则你可能有null 访问el.parentNode,因为qSA 将父母放在首位。
  • @kirilloid:嗯……我不明白。即使父母先被移除,也不应该有任何东西阻止孩子被移除(尽管这是不必要的)。还是我错过了什么?
  • 是的,我错了。分离的 DOM 节点不会自动为其子节点变为 nulls。为了优化,重新排序可能很有趣。实际上你需要“自己”走节点。
  • @kirilloid:如果我们有一个外循环,或者如果只有一个container,我们可以做if (container.compareDocumentPosition(el) &amp; 16) {
【解决方案2】:

可能有更好的方法,只是浪费了几分钟,所以我想我会玩答案。

var container = document.getElementsByClassName("container")[0];
var children = container.childNodes;

for (var i=children.length-1;i--) {

    var child = children[i];    
    if (child.nodeType===1) {  //make sure it is an element, not a text node
        var hasMatch = false;
        var attrs = child.attributes;  //get the attributes of the element
        for(var j=0; j<attrs.length;j++){  //loop through
            if(attrs[j].nodeName.indexOf("data-")===0) {  //if it starts we have a match
               hasMatch = true;
               break;
            }
        }
        if (!hasMatch) {
            container.removeChild(child);  //if no match, remove it
        }
    }
}

【讨论】:

  • +1 我会赞成,这与我想出的基本相同,而不是其他答案过于聪明愚蠢。
【解决方案3】:

@cookie monster的返工解决方案:

(function r (nodelist) {
    // reduceRight is used only to walk in reverse direction
    [].reduceRight.call(nodelist, function (dummy, e) {
        if ([].every.call(e.attributes, function(a) {
            return !/^data/i.test(a.name);
        })) return e.parentNode.removeChild(e);
        r(e.children);
    }, "filler");
}(document.getElementsByClassName("container")[0].children));

【讨论】:

  • ...除了我不认为你想要.every()。仅当当前元素的每个属性都是 data 属性时才会如此。
  • ...没关系,你是对的。我把它转过来了。没有看到正则表达式的负值。
  • 你能发个 FIDDLE
【解决方案4】:

应该这样做

var parent = document.querySelector('.container');
var elems  = parent.querySelectorAll('*');

for (var i=elems.length; i--;) {
    var attr    = elems[i].attributes,
        hasData = false;

    for (var j = attr.length; j--;) {
        if ( attr[j].name.indexOf('data') === 0 ) {
            hasData = true;
            break;
        }
    }

    if ( ! hasData ) parent.removeChild(elems[i]);
}

FIDDLE

querySelector(All) 如果您需要支持 IE7 及以下版本,则必须进行 polyfill。

【讨论】:

    【解决方案5】:

    试试这个:

    var objects = document.querySelectorAll('.container *');
    var parent = document.getElementsByClassName('container')[0];
    
    for (var i = objects.length - 1; i >= 0; i--) {
        if (objects[i].attributes[0]) {
            if (objects[i].attributes[0].name.indexOf('data-') == -1) {
                parent.removeChild(objects[i]);
            }
        } else {
            parent.removeChild(objects[i]);
        }
    }
    

    Demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多