轻松使用 DOM 有时候,您可能想要遍历 DOM,在每个节点调用函数或从每个节点返回一个值。实际上,由于这些想法非常具有普遍性,所以 DOM Level 2 已经包含了一个称为 DOM Traversal and Range 的扩展(为迭代 DOM 所有节点定义了对象和 API),它用来为 DOM 中的所有节点应用函数和在 DOM 中选择一个范围。因为这些函数没有在 Internet Explorer 中定义(至少目前是这样),所以您可以使用 nextNode() 来做一些 类似的事情。
在这里,我们的想法是创建一些简单、普通的工具,然后以不同的方式组装它们来达到预期的效果。如果您很熟悉函数式编程,这看起来会很亲切。Beyond JS 库(参阅 参考资料)将此理念发扬光大。 清单 9. 函数式 DOM 实用工具 // return an Array of all nodes, starting at startNode and // continuing through the rest of the DOM tree function listNodes(startNode) { var list = new Array(); var node = startNode; while(node) { list.push(node); node = nextNode(node); } return list; } // The same as listNodes(), but works backwards from startNode. // Note that this is not the same as running listNodes() and // reversing the list. function listNodesReversed(startNode) { var list = new Array(); var node = startNode; while(node) { list.push(node); node = prevNode(node); } return list; } // apply func to each node in nodeList, return new list of results function map(list, func) { var result_list = new Array(); for (var i = 0; i < list.length; i++) { result_list.push(func(list[i])); } return result_list; } // apply test to each node, return a new list of nodes for which // test(node) returns true function filter(list, test) { var result_list = new Array(); for (var i = 0; i < list.length; i++) { if (test(list[i])) result_list.push(list[i]); } return result_list; } 清单 9 包含了 4 个基本工具。listNodes() 和 listNodesReversed() 函数可以扩展到一个可选的长度,这与 Array 的 slice() 方法效果类似,我把这个作为留给您的练习。另一个需要注意的是,map() 和 filter() 函数是完全通用的,用于处理任何 列表(不只是节点列表)。现在,我向您展示它们的几种组合方式。 清单 10. 使用函数式实用工具 // A list of all the element names in document order function isElement(node) { return node.nodeType == Node.ELEMENT_NODE; } function nodeName(node) { return node.nodeName; } var elementNames = map(filter(listNodes(document),isElement), nodeName); // All the text from the document (ignores CDATA) function isText(node) { return node.nodeType == Node.TEXT_NODE; } function nodeValue(node) { return node.nodeValue; } var allText = map(filter(listNodes(document), isText), nodeValue); |