createNodeIterator fails in IE9 when acceptNode is specified

谁都会走 提交于 2019-12-11 01:27:26

问题


Target

I'd like to loop through DOM text nodes, sorted by their order inside the DOM. Furthermore I'd like to filter nodes by custom logic (e.g. check if a node is inside a specific element). Additionally all this should be done in the best possible performance and working in IE9+.

Method

All of the above requirements are met with either

  • document.createTreeWalker() or
  • document.createNodeIterator()

I don't fully understand why these similiar functions aren't merged together. But, as createTreeWalker() has more API methods I've started using it.

Then I found out that according to the documentation, the acceptNode filter function isn't supported in IE9. Therefore I switched over to createNodeIterator, which hasn't this restriction according to the documentation.

This is the code I'm using to loop through the elements:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Test</title>
    </head>
<body>
    <div class="context">
      Root first
        <div>
          Child
        </div>
      Root second
    </div>

    <script type="text/javascript">
        var treeWalker = document.createNodeIterator(
            document.querySelector(".context"),
            NodeFilter.SHOW_TEXT,
            {
                acceptNode: function(){
                    return NodeFilter.FILTER_ACCEPT;
                }
          },
          false
        );

        var nodeList = [];
        var currentNode;
        while (currentNode = treeWalker.nextNode()){
            nodeList.push(currentNode);
        }

        console.log(nodeList);

    </script>
</body>
</html>

While the loop actually does (almost) nothing in this case, in my real application it does. So please see this just as an example.

Issue

The problem is that the above will not work in IE9. It seems like the acceptNode filter callback property of createNodeIterator isn't supported in IE9 too. It must be null to work. However, as the documentation says it's supported, I expect it to work.

What I expect:

The actual message:

Question

What's the problem here and how to fix it? Note that I definitely need to have the loop.


回答1:


I actually have the exact same error in IE11.

If you look at the W3C documentation for Document Object Model Level 2 Traversal and Range and more specifically the Appendix C regarding ECMAScript Language Binding, the NodeFilter object is defined as the following:

This is an ECMAScript function reference. This method returns a Number. The parameter is a Node object.

So if you updates your script to pass a function instead of an object with a key acceptNode, you'll get the expected result.

var treeWalker = document.createNodeIterator(
    document.querySelector(".context"),
    NodeFilter.SHOW_TEXT,
    function(){
        return NodeFilter.FILTER_ACCEPT;
    },
    false
);

The result in Firefox will be:

In Chrome you'll get:

And in IE, you'll have:

I didn't modify your loop or anything else to get these results so I posted only the relevant part.




回答2:


I think the part where you actually have your loop is where things are messed up. I do understand what you are trying to do, but I figured a way that I believe you can use to still achieve the same results:

 try{ 
       var treeWalker = document.createNodeIterator(
         document.querySelector(".context"),
         NodeFilter.SHOW_TEXT,
         { acceptNode: function(node)
              { return NodeFilter.FILTER_ACCEPT; }
         },
      false
      );
    //This will help you avoid the loop you currently have on your code, but you wold still need one if you want to have a wrapper task that you want to perform on your treelist items

     var nodeList = treeWalker.root.childNodes;

     console.log(nodeList [0]);
 }catch(e){
   console.log(e);
 }

//Version 2

var nodeIterator = document.createNodeIterator(
    document.body,
    NodeFilter.SHOW_ELEMENT,
    function(node) {
        return node.nodeName.toLowerCase() === 'p' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
    },
    false
);
var pars = [];
//what you were missing for it to work on IE
    var currentNode = "<p></p>";


while (currentNode = nodeIterator.nextNode()) {
  console.dir(currentNode); // or console wherever you want
  pars.push(currentNode);
}


来源:https://stackoverflow.com/questions/38245898/createnodeiterator-fails-in-ie9-when-acceptnode-is-specified

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!