Efficiently retrieves which child of the parent element the current element is

  • 2020-03-26 21:31:42
  • OfStack

For example, when handling events, it is sometimes necessary to know which child node is currently clicked, while the HTML DOM itself does not directly provide the corresponding attributes, so you need to calculate by yourself.

From an index number, it is easy to get the childNodes or child elements corresponding to the index, directly using parentnode.childnodes [index] or parentnode.children [index].

Conversely, given a node or element object, it is less straightforward to know its index number.

For some special elements, the HTML DOM has corresponding attributes to represent its index number, mainly the TD and TR elements of the table.

The table cell TD element has a cellIndex attribute.

The table row TR element has a rowIndex attribute.

If your processing target happens to be a table, use these two properties first.

But regular nodes or elements don't have attributes like childNodeIndex or childElementIndex.

There are two main types of solutions:

1. Calculate and cache the index number of the node in advance (it can exist in the node attribute or js variable).

Ii. Real-time calculation requires traversing some nodes.

In the application, one of the above two schemes can be selected according to different actual conditions.

Application of scheme 1:

When the DOM structure does not change and the indexes of individual nodes need to be obtained frequently, scheme 1 can be adopted.

The advantage is that the subsequent read is fast, the disadvantage is that initialization costs, DOM structure changes need to be re-initialized.

Application of scheme 2:

The DOM structure may change, and the indexes of individual nodes are not obtained very frequently.

The advantage is that it is unaffected by DOM structure changes, does not pollute DOM structure, and has no initialization overhead. The disadvantage is that it is not suitable for high frequency invocation.

In general, it is better to adopt scenario 2, because DOM tree sizes are generally limited, and a round trip does not result in a significant reduction in overall performance, but the benefits are significant.

For Internet explorer, there is a more straightforward approach.

From IE4 to IE11, there is a sourceIndex attribute, which indicates the order of the elements in the DOM tree. It is easy to know which child the element is by comparing the difference between the sourceIndex of the element and the parent element.

I wrote a function to distinguish the processing, using the sourceIndex efficient judgment under IE, non-ie using the general traversal.
 
function getChildrenIndex(ele){ 
//IE is simplest and fastest 
if(ele.sourceIndex){ 
return ele.sourceIndex - ele.parentNode.sourceIndex - 1; 
} 
//other browsers 
var i=0; 
while(ele = ele.previousElementSibling){ 
i++; 
} 
return i; 
} 

The above function only computes the Element Element, which is the node with nodeType 1. The text node, comment node, and so on will not be counted. If all nodes need to be counted, the sourceIndex cannot be applied, because the attribute is only for element.previouselementsibling, which also needs to be changed to previousSibling.
 
function getNodeIndex(node){ 
var i=0; 
while(ele = ele.previousSibling){ 
i++; 
} 
return i; 
} 

Postscript: under the Internet explorer, have compareDocumentPosition method used to compare the node position, but after test the performance of this method is very poor, the internal implementation mechanism is definitely not like IE cache the resource index number, if this method is very efficient, it can be calculated, using dichotomy to improve efficiency, but it is not possible.

Final conclusion:

CellIndex and rowIndex attributes are preferred for table TD and TR elements.

Use the sourceIndex property first for IE.

Other scenarios use previousElementSibling or previousSibling for traversal.

The compareDocumentPosition method performs very poorly.

Related articles: