JQuery ile metin düğümlerini nasıl seçerim?


388

Bir jQuery koleksiyonu olarak bir öğenin tüm alt metin düğümlerini almak istiyorum. Bunu yapmanın en iyi yolu nedir?

Yanıtlar:


261

jQuery bunun için uygun bir işleve sahip değildir. Sen birleştirmek gerekir contents(), tıpkı çocuk düğümleri vermek ancak metin düğümlerini içerir edecek olan find()tüm alt öğeleri ama hiçbir metin düğümlerini veren. İşte ben geldim:

var getTextNodesIn = function(el) {
    return $(el).find(":not(iframe)").addBack().contents().filter(function() {
        return this.nodeType == 3;
    });
};

getTextNodesIn(el);

Not: jQuery 1.7 veya önceki bir sürümünü kullanıyorsanız, yukarıdaki kod çalışmaz. Bunu düzeltmek için addBack()ile değiştirin andSelf(). andSelf()1,8'den addBack()itibaren onaylanmamıştır .

Bu, saf DOM yöntemlerine kıyasla biraz verimsizdir ve jQuery'nin işlevini aşırı yüklemesi için çirkin bir geçici çözümcontents() içermelidir (bunu belirtmek için yorumlarda @rabidsnail sayesinde), bu yüzden basit bir özyinelemeli işlev kullanan jQuery çözümü yoktur. includeWhitespaceNodesBoşluk metin düğümleri çıkış dahil olsun ya da olmasın parametre, (jQuery otomatik olarak filtrelenir).

Güncelleme: includeWhitespaceNodes yanlış olduğunda hata düzeltildi.

function getTextNodesIn(node, includeWhitespaceNodes) {
    var textNodes = [], nonWhitespaceMatcher = /\S/;

    function getTextNodes(node) {
        if (node.nodeType == 3) {
            if (includeWhitespaceNodes || nonWhitespaceMatcher.test(node.nodeValue)) {
                textNodes.push(node);
            }
        } else {
            for (var i = 0, len = node.childNodes.length; i < len; ++i) {
                getTextNodes(node.childNodes[i]);
            }
        }
    }

    getTextNodes(node);
    return textNodes;
}

getTextNodesIn(el);

Öğe aktarılabilir mi, bir div adı olabilir mi?
crosenblum

@crosenblum: document.getElementById()İlk önce arayabilirsin , demek istediğin buysa:var div = document.getElementById("foo"); var textNodes = getTextNodesIn(div);
Tim Down

JQuery'deki bir hata nedeniyle, elinizde iframe'leriniz varsa .find ('*') yerine .find (': not (iframe)') kullanmanız gerekir.
bobpoekert

@rabidsnail: Bence, yine de kullanımı .contents(), iframe'i de arayacağını ima ediyor. Nasıl bir hata olabileceğini anlamıyorum.
Robin Maben

bugs.jquery.com/ticket/11275 Bunun gerçekten bir hata olup olmadığı tartışmaya açık gibi görünüyor, ancak olmayan bir iframe içeren bir düğümde find ('*'). dom'a eklendiğinde, tanımsız bir noktada bir istisna elde edersiniz.
bobpoekert

209

Jauco bir yorumda iyi bir çözüm gönderdi, bu yüzden buraya kopyalıyorum:

$(elem)
  .contents()
  .filter(function() {
    return this.nodeType === 3; //Node.TEXT_NODE
  });

34
aslında $ (elem) .contents () .filter (function () {return this.nodeType == Düğüm.TEXT_NODE;}); yeterli
Jauco

37
IE7 Düğümü genel olarak tanımlamaz, bu yüzden bunu kullanmanız gerekir. NodeType == 3, ne yazık ki: stackoverflow.com/questions/1423599/node-textnode-and-ie7
Christian Oudard

17
Bu yalnızca OP'nin istediği gibi öğenin torunları yerine öğenin doğrudan alt öğesi olan metin düğümlerini döndürmez mi?
Tim Down

7
Bu, metin düğümü diğer öğelerin içine derin iç içe yerleştirildiğinde çalışmaz, çünkü content
minhajul

1
@Jauco, hayır, yeterli değil! olarak .contents () sadece hemen çocuk düğümlerini döndürür
minhajul

17
$('body').find('*').contents().filter(function () { return this.nodeType === 3; });

6

jQuery.contents()ile birlikte jQuery.filtertüm alt metin düğümlerini bulmak için kullanılabilir . Küçük bir bükülme ile torun metin düğümlerini de bulabilirsiniz. Özyineleme gerekmez:

$(function() {
  var $textNodes = $("#test, #test *").contents().filter(function() {
    return this.nodeType === Node.TEXT_NODE;
  });
  /*
   * for testing
   */
  $textNodes.each(function() {
    console.log(this);
  });
});
div { margin-left: 1em; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div id="test">
  child text 1<br>
  child text 2
  <div>
    grandchild text 1
    <div>grand-grandchild text 1</div>
    grandchild text 2
  </div>
  child text 3<br>
  child text 4
</div>

jsFiddle


4

Kabul edilen filtre işleviyle çok fazla boş metin düğümü alıyordum. Yalnızca boşluk olmayan metin düğümleri seçmekle ilgileniyorsanız, basit bir işlev gibi işlevinize bir nodeValuekoşullu eklemeyi deneyin :filter$.trim(this.nodevalue) !== ''

$('element')
    .contents()
    .filter(function(){
        return this.nodeType === 3 && $.trim(this.nodeValue) !== '';
    });

http://jsfiddle.net/ptp6m97v/

Veya içeriğin boşluk gibi göründüğü, ancak görünmediği garip durumlardan (örneğin, yumuşak kısa çizgi &shy;karakteri, yeni satırlar \n, sekmeler vb.) Kaçınmak için , Normal İfade kullanmayı deneyebilirsiniz. Örneğin, \Sboşluk olmayan karakterlerle eşleşir:

$('element')
        .contents()
        .filter(function(){
            return this.nodeType === 3 && /\S/.test(this.nodeValue);
        });

3

Tüm çocukların Öğe Düğümleri veya Metin Düğümleri olduğunu varsayabilirseniz, bu bir çözümdür.

Tüm alt metin düğümlerini jquery koleksiyonu olarak almak için:

$('selector').clone().children().remove().end().contents();

Metin olmayan alt öğe kaldırılmış orijinal öğenin bir kopyasını almak için:

$('selector').clone().children().remove().end();

1
Tim Down'ın başka bir cevap hakkındaki yorumunu fark ettim. Bu çözüm sadece doğrudan çocukları alır, tüm torunları değil.
colllin

2

Bir nedenden dolayı contents()benim için işe yaramadı, bu yüzden sizin için işe yaramadıysa, işte yaptığım bir çözüm jQuery.fn.descendants, metin düğümlerini dahil etme veya eklememe seçeneğiyle oluşturdum

kullanım


Metin düğümleri ve öğe düğümleri dahil tüm torunları edinin

jQuery('body').descendants('all');

Tüm metinleri yalnızca metin düğümleri döndürme

jQuery('body').descendants(true);

Yalnızca öğe düğümlerini döndüren tüm torunları edinin

jQuery('body').descendants();

Coffeescript Orijinal :

jQuery.fn.descendants = ( textNodes ) ->

    # if textNodes is 'all' then textNodes and elementNodes are allowed
    # if textNodes if true then only textNodes will be returned
    # if textNodes is not provided as an argument then only element nodes
    # will be returned

    allowedTypes = if textNodes is 'all' then [1,3] else if textNodes then [3] else [1]

    # nodes we find
    nodes = []


    dig = (node) ->

        # loop through children
        for child in node.childNodes

            # push child to collection if has allowed type
            nodes.push(child) if child.nodeType in allowedTypes

            # dig through child if has children
            dig child if child.childNodes.length


    # loop and dig through nodes in the current
    # jQuery object
    dig node for node in this


    # wrap with jQuery
    return jQuery(nodes)

Javascript Sürümünde Bırak

var __indexOf=[].indexOf||function(e){for(var t=0,n=this.length;t<n;t++){if(t in this&&this[t]===e)return t}return-1}; /* indexOf polyfill ends here*/ jQuery.fn.descendants=function(e){var t,n,r,i,s,o;t=e==="all"?[1,3]:e?[3]:[1];i=[];n=function(e){var r,s,o,u,a,f;u=e.childNodes;f=[];for(s=0,o=u.length;s<o;s++){r=u[s];if(a=r.nodeType,__indexOf.call(t,a)>=0){i.push(r)}if(r.childNodes.length){f.push(n(r))}else{f.push(void 0)}}return f};for(s=0,o=this.length;s<o;s++){r=this[s];n(r)}return jQuery(i)}

Düzenlenmemiş Javascript sürümü: http://pastebin.com/cX3jMfuD

Bu çapraz tarayıcıdır, Array.indexOfkoda küçük bir çoklu dolgu dahildir.


1

Ayrıca şu şekilde yapılabilir:

var textContents = $(document.getElementById("ElementId").childNodes).filter(function(){
        return this.nodeType == 3;
});

Yukarıdaki kod, belirli bir öğenin doğrudan alt çocuk düğümlerinden textNodes'u filtreler.


1
... ancak tüm soyundan çocuk düğümleri (orijinal elemanının çocuğu olan bir öğenin çocuğu mesela bir metin düğümü).
Tim Down

0

tüm etiketleri çıkarmak istiyorsanız bunu deneyin

fonksiyon:

String.prototype.stripTags=function(){
var rtag=/<.*?[^>]>/g;
return this.replace(rtag,'');
}

kullanımı:

var newText=$('selector').html().stripTags();

0

Benim için sade eski .contents() metin düğümlerini döndürmek için çalışıyor gibi göründü, sadece metin düğümleri olacağını bilmek için seçicilere dikkat etmelisin.

Örneğin, bu, masamdaki TD'lerin tüm metin içeriğini preetiketlerle tamamladı ve sorun yaşamadı.

jQuery("#resultTable td").content().wrap("<pre/>")

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.