Si j'ai du HTML comme ça:
<li id="listItem">
This is some text
<span id="firstSpan">First span text</span>
<span id="secondSpan">Second span text</span>
</li>
J'essaie d'utiliser .text()
pour récupérer uniquement la chaîne "Ceci est du texte", mais si je devais dire $('#list-item').text()
, je reçois le message "Ceci est du texte textFirst span textSecond span".
Existe-t-il un moyen d'obtenir (et éventuellement de supprimer, via quelque chose comme .text("")
) uniquement le texte libre contenu dans une balise, et non le texte contenu dans ses balises enfant?
Le HTML n’a pas été écrit par moi-même, c’est pour cela que je dois travailler. Je sais qu'il serait simple d'envelopper le texte dans des balises lors de l'écriture du code HTML, mais encore une fois, le code HTML est pré-écrit.
J'ai aimé cette implémentation réutilisable basée sur la méthode clone()
trouvée ici pour obtenir uniquement le texte à l'intérieur de l'élément parent.
Code fourni pour référence facile:
$("#foo")
.clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.text();
Réponse simple:
$("#listItem").contents().filter(function(){
return this.nodeType == 3;
})[0].nodeValue = "The text you want to replace with"
Cela ressemble à un cas de surutilisation de la requête pour moi. Ce qui suit va saisir le texte en ignorant les autres nœuds:
document.getElementById("listItem").childNodes[0];
Vous aurez besoin de couper cela, mais cela vous donne ce que vous voulez en une ligne facile.
MODIFIER
Ce qui précède aura le noeud text. Pour obtenir le texte actuel, utilisez ceci:
document.getElementById("listItem").childNodes[0].nodeValue;
Plus facile et plus rapide:
$("#listItem").contents().get(0).nodeValue
Semblable à la réponse acceptée, mais sans clonage:
$("#foo").contents().not($("#foo").children()).text();
Et voici un plugin jQuery à cet effet:
$.fn.immediateText = function() {
return this.contents().not(this.children()).text();
};
Voici comment utiliser ce plugin:
$("#foo").immediateText(); // get the text without children
n'est pas le code:
var text = $('#listItem').clone().children().remove().end().text();
devenir juste jQuery pour le bien de jQuery? Lorsque des opérations simples impliquent autant de commandes chaînées et de traitements (inutiles), il est peut-être temps d'écrire une extension jQuery:
(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));
appeler:
var text = $('#listItem').textNotChild();
les arguments sont dans le cas où un scénario différent est rencontré, tel que
<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>");
le texte aura une valeur:
some text<break>again more.....second text<break>again more
Il faudra que ce soit adapté aux besoins, qui dépendent de la structure qui vous est présentée. Pour l'exemple que vous avez fourni, cela fonctionne:
$(document).ready(function(){
var $tmp = $('#listItem').children().remove();
$('#listItem').text('').append($tmp);
});
Démo: http://jquery.nodnod.net/cases/2385/run
Mais cela dépend assez du fait que le balisage soit similaire à ce que vous avez posté.
Essaye ça:
$('#listItem').not($('#listItem').children()).text()
$($('#listItem').contents()[0]).text()
Variante courte de Stuart answer.
ou avec get()
$($('#listItem').contents().get(0)).text()
jQuery.fn.ownText = function () {
return $(this).contents().filter(function () {
return this.nodeType === Node.TEXT_NODE;
}).text();
};
Je suppose que ce serait également une bonne solution, si vous souhaitez obtenir le contenu de tous les nœuds de texte qui sont des enfants directs de l'élément sélectionné.
$(selector).contents().filter(function(){ return this.nodeType == 3; }).text();
Remarque: la documentation de jQuery utilise un code similaire pour expliquer la fonction de contenu: https://api.jquery.com/contents/
P.S. Il y a aussi un moyen un peu plus laid de le faire, mais cela montre plus en détail comment les choses fonctionnent et permet un séparateur personnalisé entre les nœuds de texte (peut-être que vous voulez un saut de ligne)
$(selector).contents().filter(function(){ return this.nodeType == 3; }).map(function() { return this.nodeValue; }).toArray().join("");
C'est une vieille question, mais la meilleure des réponses est très peu efficace Voici une meilleure solution:
$.fn.myText = function() {
var str = '';
this.contents().each(function() {
if (this.nodeType == 3) {
str += this.textContent || this.innerText || '';
}
});
return str;
};
Et juste faire ceci:
$("#foo").myText();
Si la position index
du nœud de texte est fixée parmi ses frères, vous pouvez utiliser
$('parentselector').contents().eq(index).text()
Tout comme la question, j'essayais d'extraire du texte afin de le remplacer par un regex, mais je rencontrais des problèmes lorsque mes éléments internes (ie: <i>
, <div>
, <span>
, etc.) étaient également supprimés.
Le code suivant semble bien fonctionner et a résolu tous mes problèmes.
Certaines des réponses fournies ici sont utilisées, mais en particulier, le texte ne sera substitué que si l'élément est de 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;
}
});
Ce qui précède parcourt tous les éléments de la el
donnée (obtenue simplement avec $("div.my-class[name='some-name']");
. Pour chaque élément interne, il les ignore fondamentalement. Pour chaque portion de texte (déterminée par if (this.nodeType === 3)
), la substitution de regex sera appliquée. à ces éléments.
La partie this.textContent = text
remplace simplement le texte substitué, ce qui dans mon cas, je cherchais des jetons tels que [[min.val]]
, [[max.val]]
, etc.
Ce court extrait de code aidera tous ceux qui essaient de répondre à la question ... et même un peu plus.
Je propose d'utiliser le createTreeWalker pour trouver tous les éléments de texte non attachés aux éléments html (cette fonction peut être utilisée pour étendre jQuery):
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>
Je suis arrivé avec une solution spécifique qui devrait être beaucoup plus efficace que le clonage et la modification du clone. Cette solution ne fonctionne qu'avec les deux réserves suivantes, mais devrait être plus efficace que la solution actuellement acceptée:
Cela dit, voici le code:
// '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);
}
il suffit de le mettre dans un <p>
ou <font>
et de récupérer ce $ ('# listItem font'). text ()
La première chose qui m'est venue à l'esprit
<li id="listItem">
<font>This is some text</font>
<span id="firstSpan">First span text</span>
<span id="secondSpan">Second span text</span>
</li>