问题
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