Yalnızca alt etiketlere yerleştirilmemiş metni almak için .text () kullanma


386

Eğer böyle html varsa:

<li id="listItem">
    This is some text
    <span id="firstSpan">First span text</span>
    <span id="secondSpan">Second span text</span>
</li>

Ben .text()sadece "Bu bazı metin" dize almak için kullanmaya çalışıyorum , ama ben söyleyecek $('#list-item').text()olursam, "Bu bazı textFirst span textSecond span metin" olsun.

.text("")Alt etiketlerindeki metni değil, yalnızca bir etiket içindeki ücretsiz metni almanın (ve muhtemelen böyle bir şey yoluyla kaldırmanın) bir yolu var mı ?

HTML benim tarafımdan yazılmadı, bu yüzden çalışmak zorunda olduğum şey bu. Html yazarken sadece etiketleri metin sarmak için basit olacağını biliyorum, ama yine, html önceden yazılmıştır.


Ben yorumuna henüz yeterince itibar yok ve ben bilginin kaybolmasına istemeyen Çünkü bir kombinasyonu, (umarım başkasının yardımcı olur) macio.Jun 'cevabı , bir RegExp ve iStranger' cevabı için HTML ile bir textNode değiştirin Javascript ile mi? bir metin için salt metin düğümlerini aramama ve tüm oluşumları bağlantılar ile değiştirmeme izin verdi.
JDQ

Yanıtlar:


509

Burada sadece üst öğenin içindeki metni almak için clone()bulunan yönteme dayalı bu yeniden kullanılabilir uygulamayı sevdim .

Kolay başvuru için sağlanan kod:

$("#foo")
    .clone()    //clone the element
    .children() //select all the children
    .remove()   //remove all the children
    .end()  //again go back to selected element
    .text();

5
Bu çözümle metni yalnızca alt öğe olmadan alırsınız, ancak yalnızca metni değiştiremezsiniz.
BenRoe

1
1 şey almıyorum: Eğer .end () seçilen öğeye geri dönüyorsa, text () orijinal metni alt öğelerle kopyalamalıdır. Ancak pratikte, manipüle edilmiş klonumuzdaki metnin kopyalandığını görüyorum. Yani end () klon () 'a geri döner?

68
Bu, bunu yapmanın gerçekten verimsiz bir yoludur
billyonecan

5
@billyonecan, daha verimli bir yöntem önerebilir misiniz? Bu "temiz" ve "kısa" olduğu için çekici. Sen ne önerirsin?
derekmx271


364

Basit cevap:

$("#listItem").contents().filter(function(){ 
  return this.nodeType == 3; 
})[0].nodeValue = "The text you want to replace with" 

38
Etkili cevapların (yabancı veri yapıları oluşturmayan) neden daha az korkutucu görünen cevaplar kadar oylanmadığını anlamıyorum. +5 yapabilseydim.
Steven Lu

16
ve etkili cevap
Paul Carroll

9
Bu sadece daha verimli değil, aynı zamanda doğru! Bu çözüm, metnin alt öğeler arasında dağıldığı durumlara yöneliktir. +5
Kyryll Tenin Baum

15
Daha da net olmak gerekirse, IE8 + kullanıyorsanız, this.nodeType == Node.TEXT_NODEyerine kullanabilirsiniz this.nodeType == 3. IMO'yu okumak ve anlamak daha kolay.
NorTicUs

8
Bu, metni olmayan bir şeyde kullanırsanız kırılır. Bunu bir işlev olarak kullanıyorsanız ve metin .contents().filter(...)var text = $(this).contents().filter(...); if (text.length) { return text[0].nodeValue; } return "";
yazabileceğiniz veya yazamayabileceğiniz

157

Bu bana jquery'i aşırı kullanmak gibi bir durum. Aşağıdakiler diğer düğümleri yok sayarak metni yakalar:

document.getElementById("listItem").childNodes[0];

Bunu düzeltmeniz gerekecek, ancak istediğinizi tek ve kolay bir çizgide getiriyor.

DÜZENLE

Yukarıdakiler metin düğümünü alacaktır . Gerçek metni almak için şunu kullanın:

document.getElementById("listItem").childNodes[0].nodeValue;

31
En iyi cevap, bu veya 10 jQuery çağrısı zinciri için bir eklentiye ihtiyacınız yok. $('.foo')[0].childNodes[0].nodeValue.trim()
raine

5
metin içeriği birkaç düğüme ayrılırsa (crlf, metin, crlf dizisi gibi)? ua tarafından inşa edilen dom'un en basit yapıyı kullanacağına dair herhangi bir (rael-life) garantisi var mı?
çöküş

5
Tamamen en iyi cevap ... neden diğer insanlar bazen jQuery kullanıyor?
ncubica

11
Bu yalnızca <div id = "listItem"> istediğiniz <span> diğer </span> </div> metin için geçerlidir. <Div id = "listItem"> <span> istediğiniz </span> diğer metin için </div> çalışmaz
Spencer

1
Bazen sahip değilsin document. Kullanarak buraya geldim cheerio.
flaş


28

Kabul edilen cevaba benzer, ancak klonlamadan:

$("#foo").contents().not($("#foo").children()).text();

Ve işte bu amaç için bir jQuery eklentisi:

$.fn.immediateText = function() {
    return this.contents().not(this.children()).text();
};

Bu eklentiyi nasıl kullanacağınız aşağıda açıklanmıştır:

$("#foo").immediateText(); // get the text without children

T.children () içindeki t nedir?
FrEaKmAn

Bu pbjk'ın Ocak'15'te yazdığı bir çözümdür ... yine de - güzel görünüyor.
Oskar Holmkratz

1
Pek değil, @Oskar. Buradaki .contents()kısım kritik!
DUzun

Düğümleriniz kimlik kullanmıyorsa hatalı çözüm.
AndroidDev

3
@AndroidDev Seçiciyi her zaman sizin için uygun olanla değiştirebilirsiniz. Bu sadece tekniği göstermek içindir! Ayrıca bile kimlikleri olmadan çalıştığını göstermek için bir eklenti sürümünü eklendi
Düzünde

8

kod değil:

var text  =  $('#listItem').clone().children().remove().end().text();

sadece jQuery uğruna jQuery olmak? Basit işlemler birçok zincirleme komut ve bu kadar (gereksiz) işlem gerektirdiğinde, belki de bir jQuery uzantısı yazma zamanı gelmiştir:

(function ($) {
    function elementText(el, separator) {
        var textContents = [];
        for(var chld = el.firstChild; chld; chld = chld.nextSibling) {
            if (chld.nodeType == 3) { 
                textContents.push(chld.nodeValue);
            }
        }
        return textContents.join(separator);
    }
    $.fn.textNotChild = function(elementSeparator, nodeSeparator) {
    if (arguments.length<2){nodeSeparator="";}
    if (arguments.length<1){elementSeparator="";}
        return $.map(this, function(el){
            return elementText(el,nodeSeparator);
        }).join(elementSeparator);
    }
} (jQuery));

aramak:

var text = $('#listItem').textNotChild();

argümanlar farklı bir senaryo ile karşılaşıldığında, örneğin

<li>some text<a>more text</a>again more</li>
<li>second text<a>more text</a>again more</li>

var text = $("li").textNotChild(".....","<break>");

metnin değeri olacaktır:

some text<break>again more.....second text<break>again more

1
Güzel. Bunu jQuery'nin sonraki sürümü için bir çekme isteği yapmaya ne dersiniz?
Jared Tomaszewski

8

Bunu dene:

$('#listItem').not($('#listItem').children()).text()

6

Size sunduğunuz yapıya bağlı olarak, ihtiyaçlara göre uyarlanmış bir şey olması gerekir. Verdiğiniz örnek için bu işe yarar:

$(document).ready(function(){
     var $tmp = $('#listItem').children().remove();
     $('#listItem').text('').append($tmp);
});

Demo: http://jquery.nodnod.net/cases/2385/run

Ancak, işaretlemenin yayınladığınıza benzer olmasına oldukça bağlıdır.


2
Gelecekteki okuyucu dikkat: Bu cevaptaki kod, çocukları gerçek öğede öldürür. Bu cloneyöntem, amaçlanan etki değilse bu yöntemi kullanmalıdır .
Mahn

@ DotNetWala'nın cevabı aşağıdadır ve bunun yerine kullanılmalıdır. Ya da en azından .detach()yerine yöntemi kullanın .remove().
Don McCurdy


4
jQuery.fn.ownText = function () {
    return $(this).contents().filter(function () {
        return this.nodeType === Node.TEXT_NODE;
    }).text();
};

1
Anında yardım sağlayabilecek bu kod snippet'i için teşekkür ederiz. Düzgün bir açıklama , bunun neden problem için iyi bir çözüm olduğunu göstererek eğitim değerini büyük ölçüde artıracak ve benzer, ancak aynı olmayan soruları olan gelecekteki okuyucular için daha yararlı hale getirecektir. Lütfen açıklama eklemek için cevabınızı düzenleyin ve hangi sınırlamaların ve varsayımların geçerli olduğunu belirtin.
Toby Speight

3

Bu eski bir soru ama en üstteki cevap çok verimsiz. İşte daha iyi bir çözüm:

$.fn.myText = function() {
    var str = '';

    this.contents().each(function() {
        if (this.nodeType == 3) {
            str += this.textContent || this.innerText || '';
        }
    });

    return str;
};

Ve bunu yapın:

$("#foo").myText();

3

Bunun da iyi bir çözüm olacağını düşünüyorum - seçilen öğenin doğrudan alt öğesi olan tüm metin düğümlerinin içeriklerini almak istiyorsanız.

$(selector).contents().filter(function(){ return this.nodeType == 3; }).text();

Not: jQuery belgeleri, içerik işlevini açıklamak için benzer kodu kullanır: https://api.jquery.com/contents/

Not: Bunu yapmanın biraz daha çirkin bir yolu da var, ancak bu, işlerin nasıl çalıştığını daha derinlemesine gösteriyor ve metin düğümleri arasında özel ayırıcıya izin veriyor (belki orada bir satır sonu istiyorsunuz)

$(selector).contents().filter(function(){ return this.nodeType == 3; }).map(function() { return this.nodeValue; }).toArray().join("");

1

Html öğelerine bağlı olmayan tüm metin öğelerini bulmak için createTreeWalker kullanmayı öneririm (bu işlev jQuery'yi genişletmek için kullanılabilir):

function textNodesOnlyUnder(el) {
  var resultSet = [];
  var n = null;
  var treeWalker  = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, function (node) {
    if (node.parentNode.id == el.id && node.textContent.trim().length != 0) {
      return NodeFilter.FILTER_ACCEPT;
    }
    return NodeFilter.FILTER_SKIP;
  }, false);
  while (n = treeWalker.nextNode()) {
    resultSet.push(n);
  }
  return resultSet;
}



window.onload = function() {
  var ele = document.getElementById('listItem');
  var textNodesOnly = textNodesOnlyUnder(ele);
  var resultingText = textNodesOnly.map(function(val, index, arr) {
    return 'Text element N. ' + index + ' --> ' + val.textContent.trim();
  }).join('\n');
  document.getElementById('txtArea').value = resultingText;
}
<li id="listItem">
    This is some text
    <span id="firstSpan">First span text</span>
    <span id="secondSpan">Second span text</span>
</li>
<textarea id="txtArea" style="width: 400px;height: 200px;"></textarea>


1

indexMetin düğümünün konumu kardeşleri arasında sabitlenmişse,

$('parentselector').contents().eq(index).text()

1

Ne kadar esnek veya kaç vakayı kapsaması gerektiğinden emin değilsiniz, ancak örneğin, metin her zaman ilk HTML etiketlerinden önce geliyorsa - neden sadece iç etiketi HTML'yi ilk etikete bölemeyip ilkini almıyorsunuz:

$('#listItem').html().split('<span')[0]; 

ve eğer ihtiyacınız varsa daha geniş olabilir

$('#listItem').html().split('<')[0]; 

ve iki işaret arasındaki metne ihtiyacınız varsa, bir şeyden sonra ama bir şeyden önce olduğu gibi, (denenmemiş) gibi bir şey yapabilir ve if ifadelerini başlangıç ​​veya bitiş işaretleyicisine veya her ikisine birden sahip olacak kadar esnek kılmak için kullanabilirsiniz. :

var startMarker = '';// put any starting marker here
var endMarker = '<';// put the end marker here
var myText = String( $('#listItem').html() );
// if the start marker is found, take the string after it
myText = myText.split(startMarker)[1];        
// if the end marker is found, take the string before it
myText = myText.split(endMarker)[0];
console.log(myText); // output text between the first occurrence of the markers, assuming both markers exist.  If they don't this will throw an error, so some if statements to check params is probably in order...

Genellikle bu tür yararlı şeyler için yardımcı işlevler yapar, onları hatasız hale getirir ve daha sonra her zaman bu tür dize manipülasyonunu yeniden yazmak ve null referansları riske atmak yerine sık sık onlara güvenirim. Bu şekilde, işlevi yeniden kullanabilirsiniz. ve bir dizge başvurusunun neden tanımlanmamış bir referans hatası olduğunu hata ayıklayarak yeniden zaman kaybetmek zorunda kalmazsınız. Şimdiye kadarki en kısa 1 satır kodu olmayabilir, ancak yardımcı program işlevine sahip olduktan sonra, o andan itibaren bir satırdır. Kodun çoğunun, hataları önlemek için sadece orada olan veya olmayan parametreleri ele aldığını unutmayın :)

Örneğin:

/**
* Get the text between two string markers.
**/
function textBetween(__string,__startMark,__endMark){
    var hasText = typeof __string !== 'undefined' && __string.length > 0;
    if(!hasText) return __string;
    var myText = String( __string );
    var hasStartMarker = typeof __startMark !== 'undefined' && __startMark.length > 0 && __string.indexOf(__startMark)>=0;
    var hasEndMarker =  typeof __endMark !== 'undefined' && __endMark.length > 0 && __string.indexOf(__endMark) > 0;
    if( hasStartMarker )  myText = myText.split(__startMark)[1];
    if( hasEndMarker )    myText = myText.split(__endMark)[0];
    return myText;
}

// now with 1 line from now on, and no jquery needed really, but to use your example:
var textWithNoHTML = textBetween( $('#listItem').html(), '', '<'); // should return text before first child HTML tag if the text is on page (use document ready etc)

metni değiştirmeniz gerekirse, sadece kullanın $('#listItem').html( newHTML ); burada newHTML, önceden soyulmuş metne sahip bir değişkendir.
OG Sean


0

Klonun klonlanmasından ve değiştirilmesinden çok daha verimli olması gereken özel bir çözüm buldum. Bu çözüm yalnızca aşağıdaki iki ayırmayla çalışır, ancak şu anda kabul edilen çözümden daha verimli olmalıdır:

  1. Sadece metni alıyorsunuz
  2. Çıkarmak istediğiniz metin alt öğelerin önündedir

Bununla birlikte, kod İşte:

// 'element' is a jQuery element
function getText(element) {
  var text = element.text();
  var childLength = element.children().text().length;
  return text.slice(0, text.length - childLength);
}

0

Sadece soru gibi, ben metnin bir kısmını düzenli ifade ikame yapmak için özü metnin çalışıyordu ama sorunları başlamıştı nerede benim iç elemanlar (yani: <i>, <div>,<span> vs.) de kaldırılır ödendi.

Aşağıdaki kod iyi çalışıyor gibi görünüyor ve tüm sorunlarımı çözdü.

Burada verilen cevapların bazılarını kullanır, ancak özellikle yalnızca öğe olduğunda metni değiştirir nodeType === 3.

$(el).contents().each(function() { 
  console.log(" > Content: %s [%s]", this, (this.nodeType === 3));

  if (this.nodeType === 3) {
    var text = this.textContent;
    console.log(" > Old   : '%s'", text);

    regex = new RegExp("\\[\\[" + rule + "\\.val\\]\\]", "g");
    text = text.replace(regex, value);

    regex = new RegExp("\\[\\[" + rule + "\\.act\\]\\]", "g");
    text = text.replace(regex, actual);

    console.log(" > New   : '%s'", text);
    this.textContent = text;
  }
});

Yukarıdakilerin yaptığı, verilen tüm elemanlar el(basitçe elde edilmiştir $("div.my-class[name='some-name']");.) Her bir iç eleman için temelde onları göz ardı eder.if (this.nodeType === 3) ) sadece bu elemanlar için normal ifade ikame uygulanacaktır .

this.textContent = textKısmı sadece benim durumumda, ben gibi jeton arıyordu grup eklenmiş metin, yerini [[min.val]], [[max.val]]vb

Bu kısa kod alıntısı, sorunun sorduğu şeyi yapmaya çalışan herkese ve biraz daha fazlasına yardımcı olacaktır.


-1

sadece bir <p>veya<font> ve bu $ ('# listItem font'). text ()

Akla ilk gelen şey

<li id="listItem">
    <font>This is some text</font>
    <span id="firstSpan">First span text</span>
    <span id="secondSpan">Second span text</span>
</li>

6
Üzerinde çalıştığım kod benim tarafımdan oluşturulmadığı için etiketlere serbest metin koyma üzerinde kontrolüm yok. Sadece o metni alabilirsem, onu kaldırabilir ve etrafındaki etiketlerle değiştirebilirim veya istediğim her şeyi yapabilirim. Ama yine, html önceden yazılmış.
MegaMatt

Ah tamam. Sonra sonuçları filtrelemeniz gerektiğini düşünüyorum: Üzgünüm.
Dorjan

-1

Bunu deneyebilirsin

alert(document.getElementById('listItem').firstChild.data)

-2

İnnerHTML ve innerText öğelerinin aynı olup olmadığını kontrol etmek için ek bir koşul kullanın. Yalnızca bu durumlarda metni değiştirin.

$(function() {
$('body *').each(function () {
    console.log($(this).html());
    console.log($(this).text());
    if($(this).text() === "Search" && $(this).html()===$(this).text())  {
        $(this).html("Find");
    }
})
})

http://jsfiddle.net/7RSGh/


-2

Sonucu kırpabilmek için DotNetWala'yı şu şekilde kullanın:

$("#foo")
    .clone()    //clone the element
    .children() //select all the children
    .remove()   //remove all the children
    .end()  //again go back to selected element
    .text()
    .trim();

Ben gibi kısa versiyonu kullanarak document.getElementById("listItem").childNodes[0]jQuery's trim () ile işe yaramaz öğrendim .


3
Çünkü document.getElementById("listItem").childNodes[0]düz javascript, jQuery işlevine sarmanız gerekir$(document.getElementById("listItem").childNodes[0]).trim()
Red Taz

Tamam bu mantıklı. Haha. Teşekkürler!
Marion Go

1
Bu, DotNetWala'nın cevabı ile neredeyse aynıdır . Yaptığın tek şey .trim()sonuna eklendi . Bu cevap gerekli mi?
Tüm İşçiler Gerekli

-3

Ben bir jquery uzmanı değilim, ama

$('#listItem').children().first().text()

1
Bir jquery uzmanına dikkat ediyorsanız, neden önce diğer cevapları okuyarak daha fazla uzman olmuyorsunuz? ... Bunlardan biri, yazdığınızla neredeyse aynı oldu, aşağıda neden olmadığını açıklayan yorumlar iyi bir fikir.
Oskar Holmkratz

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.