The querySelector() method returns the first child element that matches a specified CSS selector(s) of an element. Note: The querySelector() method only returns the first element that matches the specified selectors. To return all the matches, use the querySelectorAll() method instead.
Use the querySelector() method to get the first child of specific type, e.g. document. querySelector('#parent > p:first-of-type') . The method returns the first element that matches the selector. If no element matches the provided selector, null is returned.
Conclusion: querySelector is usually slightly faster than getElementById when grabbing id's.
To get the nth-child of an element using the querySelector method, pass the :nth-child() pseudo-class as a parameter to the method, e.g. document. querySelector('#parent :nth-child(1)') . The nth-child pseudo-class returns the element that matches the specified position.
Though it's not a full answer, you should keep an eye on the W3C Selector API v.2 which is already available in most browser, both desktop and mobile, except IE (Edge seems to support): see full support list.
function(elem) {
return elem.querySelectorAll(':scope > someselector');
};
You can't. There's no selector that will simulate your starting point.
The way jQuery does it (more because of a way that qsa
behaves that is not to their liking), is that they check to see if elem
has an ID, and if not, they temporarily add an ID, then create a full selector string.
Basically you'd do:
var sel = '> someselector';
var hadId = true;
if( !elem.id ) {
hadID = false;
elem.id = 'some_unique_value';
}
sel = '#' + elem.id + sel;
var result = document.querySelectorAll( sel );
if( !hadId ) {
elem.id = '';
}
This certainly isn't jQuery code, but from what I remember, it is basically what they do. Not just in this situation, but in any situation where you're running a selector from the context of a nested element.
Source code for Sizzle
As avetisk has mentioned Selectors API 2 uses :scope
pseudo-selector.
To make this work in all browsers (that support querySelector
) here is the polyfill
(function(doc, proto) {
try { // check if browser supports :scope natively
doc.querySelector(':scope body');
} catch (err) { // polyfill native methods if it doesn't
['querySelector', 'querySelectorAll'].forEach(function(method) {
var nativ = proto[method];
proto[method] = function(selectors) {
if (/(^|,)\s*:scope/.test(selectors)) { // only if selectors contains :scope
var id = this.id; // remember current element id
this.id = 'ID_' + Date.now(); // assign new unique id
selectors = selectors.replace(/((^|,)\s*):scope/g, '$1#' + this.id); // replace :scope with #ID
var result = doc[method](selectors);
this.id = id; // restore previous id
return result;
} else {
return nativ.call(this, selectors); // use native code for other selectors
}
}
});
}
})(window.document, Element.prototype);
node.querySelector(':scope > someselector');
node.querySelectorAll(':scope > someselector');
For historical reasons, my previous solution
Based on all answers
// Caution! Prototype extending
Node.prototype.find = function(selector) {
if (/(^\s*|,\s*)>/.test(selector)) {
if (!this.id) {
this.id = 'ID_' + new Date().getTime();
var removeId = true;
}
selector = selector.replace(/(^\s*|,\s*)>/g, '$1#' + this.id + ' >');
var result = document.querySelectorAll(selector);
if (removeId) {
this.id = null;
}
return result;
} else {
return this.querySelectorAll(selector);
}
};
Usage
elem.find('> a');
If you want to eventually find direct children (and not e.g. > div > span
), you can try Element.matches():
const elem = document.body
const elems = [...elem.children].filter(e => e.matches('b'))
console.log(elems)
<a>1</a>
<b>2</b>
<b>3</b>
<b>4</b>
<s>5</s>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With