2010-01-11 19 views
17

雖然我從來沒有聽說過這個,但是,是否有可能使用JS從DOM中檢索節點,然後找出發生該節點的文件的哪一行?在Javascript中查找DOM中元素的行號?

我對任何東西都是開放的,替代瀏覽器插件/附加組件等......它不需要每個人都說是跨瀏覽器。

我會認爲這可能會以某種方式考慮到一些JS調試器能夠在腳本標籤內找到行號,但我不完全確定。

+0

我加入我的【答案】鏈接(http://stackoverflow.com/questions/2044642/finding-out-what-line-number-an-element-in-the-dom-occurs-on -in-javascript/2046930#2046930)到我可能感興趣的代碼的插件版本。 – 2010-01-15 06:11:02

回答

7

好吧,原諒我有多大,這是。我認爲這是一個非常有趣的問題,但在玩這個遊戲時,我很快意識到innerHTML及其同類遊戲在維護空白,評論等方面是相當不可靠的。考慮到這一點,我回到實際拉下了完整副本來源,這樣我就可以絕對確定我有完整的來源。然後,我使用jquery和一些(相對較小的)正則表達式來查找每個節點的位置。雖然我確信我錯過了一些邊緣案例,但它似乎運作良好。而且,是的,是的,正則表達式和兩個問題,等等等等。

編輯:作爲構建jQuery插件的鍛鍊,我修改我的代碼的功能相當好作爲一個獨立的pluginexample類似下面發現的HTML(我將離開這裏爲後人)。我試圖讓代碼稍微更健壯一些(比如現在在帶引號的字符串中處理標籤,比如onclick),但是最大的缺陷是它無法解釋頁面的任何修改,比如附加元素。我需要可能需要使用iframe而不是ajax調用來處理這種情況。

<html> 
    <head id="node0"> 
    <!-- first comment --> 
     <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> 
     <style id="node1"> 
/*   div { border: 1px solid black; } */ 
      pre { border: 1px solid black; } 
     </style> 
    <!-- second comment --> 
     <script> 
      $(function() { 

       // fetch and display source 
       var source; 
       $.ajax({ 
        url: location.href, 
        type: 'get', 
        dataType: 'text', 
        success: function(data) { 
         source = data; 


         var lines = data.split(/\r?\n/); 
         var html = $.map(lines, function(line, i) { 
          return ['<span id="line_number_', i, '"><strong>', i, ':</strong> ', line.replace(/</g, '&lt;').replace(/>/g, '&gt;'), '</span>'].join(''); 
         }).join('\n'); 

         // now sanitize the raw html so you don't get false hits in code or comments 
         var inside = false; 
         var tag = ''; 
         var closing = { 
          xmp: '<\\/\\s*xmp\\s*>', 
          script: '<\\/\\s*script\\s*>', 
          '!--': '-->' 
         }; 
         var clean_source = $.map(lines, function(line) { 
          if (inside && line.match(closing[tag])) { 
           var re = new RegExp('.*(' + closing[tag] + ')', 'i'); 
           line = line.replace(re, "$1"); 
           inside = false; 
          } else if (inside) { 
           line = ''; 
          } 

          if (line.match(/<(script|!--)/)) { 
           tag = RegExp.$1; 
           line = line.replace(/<(script|xmp|!--)[^>]*.*(<(\/(script|xmp)|--)?>)/i, "<$1>$2"); 
           var re = new RegExp(closing[tag], 'i'); 
           inside = ! (re).test(line); 
          } 
          return line; 
         }); 

         // nodes we're looking for 
         var nodes = $.map([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(num) { return $('#node' + num) }); 

         // now find each desired node in both the DOM and the source 
         var line_numbers = $.map(nodes, function(node) { 
          var tag = node.attr('tagName'); 
          var tags = $(tag); 
          var index = tags.index(node) + 1; 

          var count = 0; 
          for (var i = 0; i < clean_source.length; i++) { 
           var re = new RegExp('<' + tag, 'gi'); 
           var matches = clean_source[i].match(re); 
           if (matches && matches.length) { 
            count += matches.length; 
            if (count >= index) { 
             console.debug(node, tag, index, count, i); 
             return i; 
            } 
           } 
          } 


          return count; 
         }); 

         // saved till end to avoid affecting source html 
         $('#source_pretty').html(html); 
         $('#source_raw').text(source); 
         $('#source_clean').text(clean_source.join('\n')); 

         $.each(line_numbers, function() { $('#line_number_' + this).css('background-color', 'orange'); }); 
        }, 
       }); 

       var false_matches = [ 
        "<div>", 
        "<div>", 
        "</div>", 
        "</div>" 
       ].join(''); 

      }); 
     </script> 
    </head> 
    <!-- third comment --> 
    <body id="node2"> 
     <div> 
      <pre id="source_pretty"> 
      </pre> 
      <pre id="source_raw"> 
      </pre> 
      <pre id="source_clean"> 
      </pre> 
     </div> 

     <div id="node3"> 
      <xmp> 
       <code> 
       // <xmp> is deprecated, you should put it in <code> instead 
       </code> 
      </xmp> 
     </div> 

    <!-- fourth comment --> 
<div><div><div><div><div><div><span><div id="node4"><span><span><b><em> 
<i><strong><pre></pre></strong></i><div><div id="node5"><div></div></div></div></em> 
</b></span><span><span id="node6"></span></span></span></div></span></div></div></div></div></div></div> 


     <div> 
      <div> 
       <div id="node7"> 
        <div> 
         <div> 
          <div id="node8"> 
           <span> 
    <!-- fifth comment --> 
            <div> 
             <span> 
              <span> 
               <b> 
                <em id="node9"> 
                 <i> 
                  <strong> 
                   <pre> 
                   </pre> 
                  </strong> 
                 </i> 
                 <div> 
                  <div> 
                   <div> 
                   </div> 
                  </div> 
                 </div> 
                </em> 
               </b> 
              </span> 
              <span> 
               <span id="node10"> 
               </span> 
              </span> 
             </span> 
            </div> 
           </span> 
          </div> 
         </div> 
        </div> 
       </div> 
      </div> 
     </div> 
    </body> 
</html> 
+0

也許你和我應該不斷嘗試這個代碼,並調整它,直到我們做對了。你試過什麼瀏覽器? – leeand00 2010-01-12 13:39:31

+0

(因爲我沒有要求跨瀏覽器的解決方案,而只是一些工作)。 – leeand00 2010-01-12 13:42:52

+0

+1努力! :) – leeand00 2010-01-12 14:01:47

1

這可以做到。通過獲取最高的節點像這樣的文件中啓動:

var htmlNode = document.getElementsByTagName('html')[0]; 
var node = htmlNode; 
while (node.previousSibling !== null) { 
    node = node.previousSibling; 
} 
var firstNode = node; 

(此代碼測試和檢索的同時doctype節點,以及在html節點上述評論)通過所有節點

然後你循環(兄弟姐妹和孩子)。在IE中,你只會看到元素和註釋(而不是文本節點),所以最好使用FF或者chrome或者其他東西(你說它不必跨瀏覽器)。

當您看到每個text node時,解析它以查找回車。

+4

如果元素標記內有新行,例如屬性之間會出現什麼內容?你不會錯過這些換行嗎? – thejoshwolfe 2012-10-30 23:13:05

1

是這樣的?

var wholeDocument = document.getElementsByTagName('html')[0] 
var findNode = document.getElementById('whatever') 
var documentUpToFindNode = wholeDocument.substr(0, wholeDocument.indexOf(findNode.outerHTML)) 
var nlsUpToFindNode = documentUpToFindNode.match(/\n/g).length 
+2

'findNode.outerHTML'對於那個元素不一定是唯一的...... – James 2010-01-11 20:39:38

+0

值+ 1 ...或+ x如果頁面在標準模式下使用DOCTYPE和/或HTML打開標記之前的附加註釋呈現。 – scunliffe 2010-01-11 20:39:49

+1

'outerHTML'是一個非標準的,僅限IE的屬性,所以這在其他瀏覽器中不起作用,正如@ J-P所指出的,不能保證對元素是唯一的。 – 2010-01-11 21:05:41

-2

你可以嘗試: -

- start at the 'whatever' node, 
- traverse to each previous node back to the doc begining while concatenating the html of each node, 
- then count the new lines in your collected HTML. 

後,一旦你螺母它怎麼把代碼那是一個很好的問題:)

+0

這假定每行只有一個HTML節點,我不確定這會起作用 – 2017-01-05 14:16:38

+0

不是。然而,它比我最初說的容易:你只需將body html作爲一個字符串,將它拆分爲你想要使用elem id的行號的元素,然後計算split的第一個成員中的換行符; – ekerner 2017-02-10 14:01:58