简体   繁体   English

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

[英]querySelector, get elements whose attribute begins with given string

I'm looking for a way to find all elements that contain an attribute that begins witha a given string. 我正在寻找一种方法来查找包含以给定字符串开头的属性的所有元素。 For example: 例如:

document.querySelectorAll('[ng-*]') would return all elements with Angular directives ( ng-click , ng-show , ng-hide ...). document.querySelectorAll('[ng-*]')将返回所有带有Angular指令的元素( ng-clickng-showng-hide ...)。

But the wildcard does not seem to work. 但是通配符似乎不起作用。

Any ideas? 有任何想法吗? I could implement my own, but it wouldn't be as effective. 我可以实施自己的方法,但是效果不佳。

There's no CSS selector that lets you do wildcards on the name of an attribute, just on the value, which obviously isn't want you want. 没有CSS选择器可让您对属性名称 (仅对值)进行通配符,而这显然是您不想要的。

Unfortunately, you'll have to do the work manually. 不幸的是,您将必须手动进行工作。

If you know the list you'll be processing will be small, you can do it with a naive version query-then-filter; 如果您知道要处理的列表很小,可以使用朴素的query-then-filter版本; if you think it may be larger, a DOM walker solution (see below) would probably be better. 如果您认为它可能更大,那么DOM Walker解决方案(请参阅下文)可能会更好。

The naive query-then-filter (ES2015 syntax): 天真的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); 
 <div></div> <div ng-bar></div> <div></div> <div ng-foo></div> <div></div> 

ES5 version: 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); 
 <div></div> <div ng-bar></div> <div></div> <div ng-foo></div> <div></div> 


Walker solution (ES2015+): 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); 
 <div></div> <div ng-bar></div> <div></div> <div> <div> <div ng-foo></div> </div> <div ng-baz></div> </div> <div></div> 

ES5: 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); 
 <div></div> <div ng-bar></div> <div></div> <div> <div> <div ng-foo></div> </div> <div ng-baz></div> </div> <div></div> 


For all of the above, note that String#startsWith may need a shim prior to ES2015. 对于上述所有内容,请注意,在ES2015之前, String#startsWith可能需要填充。

@TJCrowder's answer is right in everything. @TJCrowder的答案是正确的。

But IMK a faster way to implement a custom querySelector method should definitely be done with a TreeWalker . 但是IMK更快地实现自定义querySelector方法的方法肯定应该使用TreeWalker完成。

Here is a simple (probably not perfect) implementation of what you are after, using the ng- filtering proposed by TJ: 这是使用TJ提出的ng-过滤实现的简单(可能不完美)的实现:

 var filterAttr = function(element) { return Array.prototype.some.call( element.attributes, function(attr) { return attr.nodeName.indexOf("ng-") === 0; } // webkit defaults to FILTER_REJECT ) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; }; // IE doesn't like {acceptNode:...} object filterAttr.acceptNode = filterAttr; var treeWalker = document.createTreeWalker( document.body, NodeFilter.SHOW_ELEMENT, filterAttr, false ); var nodeList = []; while (treeWalker.nextNode()) { nodeList.push(treeWalker.currentNode); } console.log(nodeList); 
 <div></div> <div ng-bar></div> <div></div> <div> <div> <div ng-foo></div> </div> <div ng-baz></div> </div> <div></div> 

PS: any upvote on this answer should also be rewarded to TJ's one too. PS: 对此答案的任何赞扬也应归功于TJ。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM