querySelector,获取其属性以给定字符串开头的元素

Jo *_*ina 0 javascript html5 dom selectors-api

我正在寻找一种方法来查找包含以给定字符串开头的属性的所有元素。例如:

document.querySelectorAll('[ng-*]')将返回与角指令的所有元素(ng-clickng-showng-hide...)。

但是通配符似乎不起作用。

有任何想法吗?我可以实施自己的方法,但是效果不佳。

T.J*_*der 5

没有CSS选择器可让您对属性名称(仅对值)进行通配符,而这显然是您不想要的。

不幸的是,您将必须手动进行工作。

如果您知道要处理的列表很小,可以使用朴素的query-then-filter版本;如果您认为它可能更大,那么DOM Walker解决方案(请参阅下文)可能会更好。

天真的query-then-filter(ES2015语法):

// Best if you can use *some* selector in the querySelectorAll rather than just *
// to keep the list to a minimum
let elements =
  [...document.querySelectorAll("*")].filter(
    element => [...element.attributes].some(
      attr => attr.nodeName.startsWith("ng-")
    )
  );
console.log(elements);
Run Code Online (Sandbox Code Playgroud)
<div></div>
<div ng-bar></div>
<div></div>
<div ng-foo></div>
<div></div>
Run Code Online (Sandbox Code Playgroud)

ES5版本:

var elements = Array.prototype.filter.call(
  document.querySelectorAll("*"), // Best if you can use *something* here
                                  // to keep the list to a minimum
  function(element) {
    return Array.prototype.some.call(
      element.attributes,
      function(attr) {
        return attr.nodeName.startsWith("ng-");
      }
    );
  }
);
console.log(elements);
Run Code Online (Sandbox Code Playgroud)
<div></div>
<div ng-bar></div>
<div></div>
<div ng-foo></div>
<div></div>
Run Code Online (Sandbox Code Playgroud)


Walker解决方案(ES2015 +):

function domFind(element, predicate, results = []) {
  if (!element.children) {
    throw new Error("Starting node must be an element or document");
  }
  if (predicate(element)) {
    results.push(element);
  }
  if (element.children && element.children.length) {
    [...element.children].forEach(child => {
      domFind(child, predicate, results);
    });
  }
  return results;
}
let elements = domFind(document, element => {
  return element.attributes && [...element.attributes].some(attr => attr.nodeName.startsWith("ng-"));
});
console.log(elements);
Run Code Online (Sandbox Code Playgroud)
<div></div>
<div ng-bar></div>
<div></div>
<div>
  <div>
    <div ng-foo></div>
  </div>
  <div ng-baz></div>
</div>
<div></div>
Run Code Online (Sandbox Code Playgroud)

ES5:

function domFind(element, predicate, results) {
  if (!results) {
    results = [];
  }
  if (!element.children) {
    throw new Error("Starting node must be an element or document");
  }
  if (predicate(element)) {
    results.push(element);
  }
  if (element.children && element.children.length) {
    Array.prototype.forEach.call(element.children, function(child) {
      domFind(child, predicate, results);
    });
  }
  return results;
}
var elements = domFind(document, function(element) {
  return element.attributes && Array.prototype.some.call(element.attributes, function(attr) {
    return attr.nodeName.startsWith("ng-");
  });
});
console.log(elements);
Run Code Online (Sandbox Code Playgroud)
<div></div>
<div ng-bar></div>
<div></div>
<div>
  <div>
    <div ng-foo></div>
  </div>
  <div ng-baz></div>
</div>
<div></div>
Run Code Online (Sandbox Code Playgroud)


对于上述所有内容,请注意,String#startsWith在ES2015之前可能需要填充垫片。