2009-09-27 38 views
4

我想获取用户突出显示区域中的所有元素。问题是,当元素位于树的不同部分时,我不知道如何遍历DOM的不同部分。到目前为止,我的代码只能从选择范围的startContainer中获取元素。我需要某种递归吗?这里是我的代码:如何获取突出显示的所有元素

getSelectedElementTags:function() 
{ 
    var range, sel, container; 
    sel = content.window.getSelection(); 
    if (sel.getRangeAt) 
    { 
     if (sel.rangeCount > 0) 
     { 
      range = sel.getRangeAt(0);    
     } 
    } 
    else 
    {  
     range = content.window.createRange(); 
     range.setStart(sel.anchorNode, sel.anchorOffset); 
     range.setEnd(sel.focusNode, sel.focusOffset); 
     alert("range created"); 
    } 


    if (range) 
    { 
     container = range["startContainer"]; 
     var elms = container.parentNode.getElementsByTagName("*");   
     elmlist = "parent: "+container.parentNode.tagName + " (" + elms.length + ")\n"; 
     for (i in elms) 
     { 
      if (elms[i].tagName != null) 
      { 
       elmlist += elms[i].tagName+"\n"; 
      } 
     } 

     alert(elmlist); 
    } 
}, 
+0

你可以使用jQuery吗?哪些浏览器必须工作(请不要全部说明,因为我怀疑支持Netscape 4)。 – 2009-09-27 05:33:55

+0

只是Firefox,因为这是一个扩展。 – 2009-09-27 06:36:03

回答

16

你可以使用document.createTreeWalker使用TreeWalker。下面是一个例子。它列出了部分或全部选定的所有元素。您可以通过修改传递给document.createTreeWalker的参数来轻松更改行为。

请注意,在Firefox中,您不需要检查是否存在选择的getRangeAt方法。此检查仅适用于较旧版本的WebKit。另外,IE < 9不支持TreeWalker或Range,因此以下内容在这些浏览器中不起作用。

编辑根据下面的注释修复。

function rangeIntersectsNode(range, node) { 
    var nodeRange; 
    if (range.intersectsNode) { 
     return range.intersectsNode(node); 
    } else { 
     nodeRange = node.ownerDocument.createRange(); 
     try { 
      nodeRange.selectNode(node); 
     } catch (e) { 
      nodeRange.selectNodeContents(node); 
     } 

     return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 && 
      range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1; 
    } 
} 

function getSelectedElementTags(win) { 
    var range, sel, elmlist, treeWalker, containerElement; 
    sel = win.getSelection(); 
    if (sel.rangeCount > 0) { 
     range = sel.getRangeAt(0); 
    } 

    if (range) { 
     containerElement = range.commonAncestorContainer; 
     if (containerElement.nodeType != 1) { 
      containerElement = containerElement.parentNode; 
     } 

     treeWalker = win.document.createTreeWalker(
      containerElement, 
      NodeFilter.SHOW_ELEMENT, 
      function(node) { return rangeIntersectsNode(range, node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT; }, 
      false 
     ); 

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

     console.log(elmlist); 
    } 
} 

<input type="button" onclick="getSelectedElementTags(window)" value="Get selected elements"> 
+0

非常感谢Tim,它的效果非常好。只有一个小问题...当一个元素被选中时,列表是空的。 – 2009-09-27 17:43:49

+0

不知道这是否是最好的方法,但我通过测试来解决问题,如果startContainer和endContainer的范围相同。如果它们是相同的,我会跳过treewalker并获取startContainer的parentNode。 – 2009-09-27 19:14:41

+0

你是对的。有两个问题:第一,我忘了将第一个节点包含在TreeWalker的列表中,第二,如果整个选择包含在单个文本节点中,则不会返回任何元素。两者现在都在解决。 – 2009-09-27 20:43:41

相关问题