Let's first talk about what these two methods should return according to W3C specifications:
querySelector:
return the first matching Element node within the node's subtrees. If there is no such node, the method must return null. (Returns the first in the set that matches the selector in the subtree of the specified element node. If there is no match, returns null)
querySelectorAll:
return a NodeList containing all of the matching Element nodes within the node's subtrees, in document order. If there are no such nodes, the method must return an empty NodeList. (Return the matching selector in the subtree of the specified element node. The node set uses depth-first pre-search; if there is no match, this method returns an empty set)
Usage:
var element = baseElement.querySelector(selectors);
var elementList = baseElement.querySelectorAll(selectors);
There is no problem when BaseElement is a document, and the implementation of each browser is basically the same; however, when BaseElement is an ordinary dom Node (dom Node that supports these two methods), The browser implementation is a bit strange, for example:
< script type="text/javascript">
var testElement= document.getElementById('testId');
var element = testElement.querySelector('.test span');
var elementList = document. querySelectorAll('.test span');
console.log(element); //
Test console.log(elementList); // 1
According to the W3C understanding, this example should return: element: null; elementList: []; because there is no matching child node that matches selectors in testElement as baseElement; but the browser seems to Ignore baseElement and only care about selectors, which means baseElement is almost document at this time; this is inconsistent with our expected results. Maybe as browsers continue to upgrade, this issue will be unified!
Human wisdom is always infinite. Andrew Dupont invented a method to temporarily correct this strange problem, which is to specify the id of baseElement in front of selectors to limit the matching range; this method is widely used in major popular frameworks in;
Jquery implementation:
var oldContext = context,
old = context.getAttribute( "id" ),
nid = old || id,
try {
if ( !relativeHierarchySelector || hasParent ) {
return makeArray( context.querySelectorAll( "[id='" nid "'] " query ), extra );
}
} catch(pseudoError) {}
finally {
if ( !old ) { oldContext.removeAttribute( "id" );}
}
Don’t look at other places in this code, just look at how it implements this method; this code is JQuery1.6 Fragment; when baseElement has no ID, set an id = "__sizzle__" for it, and then add it in front of selectors when using it to limit the range; context.querySelectorAll( "[id='" nid "'] " query ; Finally, because this ID itself is not what baseElement should have, it needs to be removed: oldContext.removeAttribute( "id" );
, Mootools implementation:
var currentId = _context.getAttribute('id'), slickid = 'slickid__';
_context. setAttribute('id', slickid);
_expression = '#' slickid ' ' _expression;
context = _context.parentNode;
Mootools is similar to Jquery: except slickid = ' slickid__'; In fact, the meaning is the same;
Method compatibility: FF3.5 /IE8 /Chrome 1 /opera 10 /Safari 3.2;
IE 8: baseElement is not supported as object;
Thank you very much for Daniel JK’s reply and provided another method.