Comment puis-je sélectionner des noeuds de texte avec jQuery?

je voudrais obtenir tous les noeuds de texte descendants d'un élément, comme une collection jQuery. Quelle est la meilleure façon de le faire?

367
demandé sur Christian Oudard 2008-11-18 16:45:09

11 réponses

jQuery n'a pas de fonction pratique pour cela. Vous devez combiner contents() , qui donnera juste des noeuds enfant mais inclut des noeuds texte , avec find() , qui donne tous les éléments descendants mais pas de noeuds texte. Voici ce que j'ai trouvé:

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

getTextNodesIn(el);

Note: Si vous utilisez jQuery 1.7 ou une version antérieure, le code ci-dessus ne fonctionnera pas. Pour le fixer, remplacer addBack() par andSelf() . andSelf() est déprécié en faveur de addBack() à partir du 1.8.

c'est quelque peu inefficace par rapport aux méthodes DOM pures et doit inclure une mauvaise solution pour la surcharge de jQuery de son contents() fonction (merci à @rabidsnail dans les commentaires pour avoir souligné cela), donc voici non-jQuery solution en utilisant une simple fonction récursive. Le paramètre includeWhitespaceNodes contrôle si oui ou non les noeuds de texte whitespace sont inclus dans la sortie (dans jQuery ils sont automatiquement filtrés).

mise à jour: Correction d'un bug lorsque includeWhitespaceNodes est falsy.

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);
246
répondu Tim Down 2015-02-12 09:47:04

Jauco a posté une bonne solution dans un commentaire, donc je le Copie ici:

$(elem)
  .contents()
  .filter(function() {
    return this.nodeType === 3; //Node.TEXT_NODE
  });
200
répondu Christian Oudard 2012-08-13 14:37:20
$('body').find('*').contents().filter(function () { return this.nodeType === 3; });
15
répondu He Nrik 2012-10-12 15:31:27

jQuery.contents() peut être utilisé avec jQuery.filter pour trouver tous les noeuds de texte enfant. Avec un peu de twist, vous pouvez trouver des petits-enfants noeuds de texte aussi bien. Pas de récursivité requis:

$(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

5
répondu Salman A 2016-01-04 20:48:16

je recevais beaucoup de noeuds de texte vides avec la fonction de filtre acceptée. Si vous êtes seulement intéressé à sélectionner des noeuds de texte qui contiennent des espaces non-blancs, essayez d'ajouter un nodeValue conditionnel à votre filter fonction, comme un simple $.trim(this.nodevalue) !== '' :

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

http://jsfiddle.net/ptp6m97v /

ou pour éviter des situations étranges où le contenu ressemble à de l'espace blanc, mais ne l'est pas (par exemple le soft tiret &shy; caractère, nouvelles lignes \n , onglets, etc.), vous pouvez essayer d'utiliser une Expression Régulière. Par exemple, \S correspondra à tous les caractères autres que les espaces:

$('element')
        .contents()
        .filter(function(){
            return this.nodeType === 3 && /\S/.test(this.nodeValue);
        });
3
répondu Alex W 2014-10-13 18:03:57

si vous pouvez faire l'hypothèse que tous les enfants sont des Noeuds D'élément ou des noeuds de texte, alors c'est une solution.

Pour avoir des enfants tous les nœuds de texte comme jquery collection:

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

pour obtenir une copie de l'élément original avec des enfants non textuels enlevés:

$('selector').clone().children().remove().end();
2
répondu colllin 2011-04-20 14:59:09

peut aussi être fait comme ceci:

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

le code ci-dessus filtre les textNodes à partir des noeuds enfants directs d'un élément donné.

1
répondu Mr_Green 2013-10-18 05:28:15

pour une raison quelconque contents() n'a pas fonctionné pour moi, donc si cela n'a pas fonctionné pour vous, voici une solution que j'ai faite, j'ai créé jQuery.fn.descendants avec l'option d'inclure des noeuds de texte ou non

Utilisation


Obtenir tous les descendants, y compris les nœuds de texte et les nœuds d'élément

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

Obtenir tous les descendants en ne retournant que les nœuds de texte

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

Obtenir tous les descendants en ne retournant que les nœuds d'élément

jQuery('body').descendants();

Coffeescript Original :

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)

Drop En Version Javascript

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)}

version Javascript non diminuée: http://pastebin.com/cX3jMfuD

c'est cross browser, un petit polyfill Array.indexOf est inclus dans le code.

1
répondu iConnor 2014-02-23 20:19:46

si vous voulez enlever toutes les étiquettes, puis essayer ce

fonction:

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

utilisation:

var newText=$('selector').html().stripTags();
0
répondu Rahen Rangan 2011-06-22 18:36:14

pour moi, le vieux .contents() semblait fonctionner pour retourner les noeuds de texte, il suffit d'être prudent avec vos sélecteurs de sorte que vous savez qu'ils seront des noeuds de texte.

par exemple, cela a enveloppé tout le contenu du TDS dans ma table avec des étiquettes pre et n'a eu aucun problème.

jQuery("#resultTable td").content().wrap("<pre/>")
0
répondu davenpcj 2013-08-23 14:41:21

j'ai eu le même problème et résolu:

Code:

$.fn.nextNode = function(){
  var contents = $(this).parent().contents();
  return contents.get(contents.index(this)+1);
}

Utilisation:

$('#my_id').nextNode();

est comme next() mais renvoie aussi les noeuds de texte.

0
répondu Guillermo 2014-02-16 05:22:57