2010-03-28 40 views
6

Dự án hiện tại của tôi liên quan đến việc thu thập nội dung văn bản từ một phần tử và tất cả các phần tử của nó, dựa trên bộ chọn được cung cấp.JavaScript: Cách nhận văn bản từ tất cả các hậu duệ của một phần tử, bỏ qua các tập lệnh?

Ví dụ, khi cung cấp bộ chọn #content và chạy với HTML này:

<div id="content"> 
    <p>This is some text.</p> 
    <script type="text/javascript"> 
    var test = true; 
    </script> 
    <p>This is some more text.</p> 
</div> 

kịch bản của tôi sẽ trở lại (sau khi dọn dẹp một chút khoảng trắng):

Đây là một số văn bản. var test = true; Đây là một số văn bản.

Tuy nhiên, tôi cần bỏ qua các nút văn bản xảy ra trong các yếu tố <script>.

Đây là một đoạn trích của mã hiện tại của tôi (về mặt kỹ thuật, nó phù hợp dựa trên một hoặc selectors cung cấp nhiều hơn):

// get text content of all matching elements 
for (x = 0; x < selectors.length; x++) { // 'selectors' is an array of CSS selectors from which to gather text content 
    matches = Sizzle(selectors[x], document); 
    for (y = 0; y < matches.length; y++) { 
    match = matches[y]; 
    if (match.innerText) { // IE 
     content += match.innerText + ' '; 
    } else if (match.textContent) { // other browsers 
     content += match.textContent + ' '; 
    } 
    } 
} 

Đó là một chút quá đơn giản ở chỗ nó chỉ trả về tất cả các nút văn bản trong phần tử (và con cháu của nó) khớp với bộ chọn được cung cấp. Giải pháp tôi đang tìm kiếm sẽ trả lại tất cả các nút văn bản ngoại trừ các nút nằm trong các phần tử <script>. Nó không cần phải có hiệu suất đặc biệt cao, nhưng tôi cần nó để cuối cùng là tương thích giữa các trình duyệt.

Tôi giả sử rằng tôi sẽ cần phải bằng cách nào đó lặp qua tất cả các phần tử con khớp với công cụ chọn và tích lũy tất cả các nút văn bản khác với các nút trong các phần tử <script>; nó không giống như bất kỳ cách nào để xác định JavaScript khi nó đã được cuộn vào chuỗi được tích lũy từ tất cả các nút văn bản.

Tôi không thể sử dụng jQuery (vì lý do hiệu suất/băng thông), mặc dù bạn có thể nhận thấy rằng tôi sử dụng công cụ chọn Sizzle của nó, vì vậy logic chọn của jQuery có sẵn.

Cảm ơn bạn đã giúp đỡ!

Trả lời

8
function getTextContentExceptScript(element) { 
    var text= []; 
    for (var i= 0, n= element.childNodes.length; i<n; i++) { 
     var child= element.childNodes[i]; 
     if (child.nodeType===1 && child.tagName.toLowerCase()!=='script') 
      text.push(getTextContentExceptScript(child)); 
     else if (child.nodeType===3) 
      text.push(child.data); 
    } 
    return text.join(''); 
} 

Hoặc, nếu bạn được phép thay đổi DOM để loại bỏ các yếu tố <script> (mà thường không có tác dụng phụ đáng kể), nhanh hơn:

var scripts= element.getElementsByTagName('script'); 
while (scripts.length!==0) 
    scripts[0].parentNode.removeChild(scripts[0]); 
return 'textContent' in element? element.textContent : element.innerText; 
+0

Tuyệt vời, cảm ơn, bobince! Tôi đã đi với cách tiếp cận đầu tiên - có lẽ bạn đang phải loại bỏ '

2

EDIT:

Vâng đầu tiên hãy để tôi nói im không quá quen với sizzle trên cô đơn của mình, jsut trong thư viện mà sử dụng nó ... Điều đó nói rằng ..

nếu tôi đã phải làm điều này tôi sẽ làm một cái gì đó như:

var selectors = new Array('#main-content', '#side-bar'); 
function findText(selectors) { 
    var rText = ''; 
    sNodes = typeof selectors = 'array' ? $(selectors.join(',')) : $(selectors); 
    for(var i = 0; i < sNodes.length; i++) { 
     var nodes = $(':not(script)', sNodes[i]); 
     for(var j=0; j < nodes.length; j++) { 
     if(nodes[j].nodeType != 1 && node[j].childNodes.length) { 
      /* recursion - this would work in jQ not sure if 
       * Sizzle takes a node as a selector you may need 
       * to tweak. 
       */ 
      rText += findText(node[j]); 
     } 
     } 
    } 

    return rText; 
} 

Tôi đã không kiểm tra bất kỳ điều nào nhưng nó sẽ cung cấp cho bạn một ý tưởng. Hy vọng rằng ai đó sẽ ống với hướng hơn :-)


Cant bạn chỉ cần lấy node cha và kiểm tra nodeName trong vòng lặp của bạn ... như:

if(match.parentNode.nodeName.toLowerCase() != 'script' && match.nodeName.toLowerCase() != 'script') { 
    match = matches[y]; 
    if (match.innerText) { // IE 
     content += match.innerText + ' '; 
    } else if (match.textContent) { // other browsers 
     content += match.textContent + ' '; 
    } 
} 

ofcourse jquery hỗ trợ not() cú pháp trong bộ chọn để bạn có thể chỉ cần $(':not(script)')?

+0

Cảm ơn prodigitalson - Tôi không chắc chắn rằng điều này sẽ hoàn thành mục tiêu của tôi, mặc dù. Tôi có thể có một chút mơ hồ trong ví dụ mã của tôi (chỉ cần chỉnh sửa nó) - những gì nó làm là đi qua một mảng các bộ chọn CSS, và cho mỗi cái khớp với một nút DOM, nó đơn giản lấy innerText (IE) hoặc textContent (khác) thuộc tính của nút đó. Nó không thực sự lặp lại thông qua các con của các phần tử. Tuy nhiên, tôi nghĩ rằng sau này có thể là cách tốt nhất để làm điều này - lặp qua tất cả các hậu duệ của phần tử đã so khớp, bỏ qua các nút văn bản trong