'innerText' fonctionne dans IE, mais pas dans Firefox

289

J'ai du code JavaScript qui fonctionne dans IE contenant les éléments suivants:

myElement.innerText = "foo";

Cependant, il semble que la propriété 'innerText' ne fonctionne pas dans Firefox. Existe-t-il un équivalent de Firefox? Ou existe-t-il une propriété plus générique, multi-navigateurs, qui peut être utilisée?

Rayon
la source
3
Cela devrait le faire myElement.innerHTML = "foo";
stefita
Cela remplacera TOUT le HTML de l'objet par la valeur fournie.
OMG Ponies
24
C'est là que les bibliothèques comme jQuery facilitent la vie car elles gèrent les incohérences entre les navigateurs comme celle-ci en vous permettant d'utiliser un cadre standard.
Dan Diplo
Mais cela pourrait toujours convenir s'il n'y a pas de HTML à prendre en charge.
Alex Polo
21
Dites-nous donc comment utiliser cette alternative multi-navigateurs au lieu de simplement dire que c'est possible (ce qui n'est pas constructif).
SasQ

Réponses:

249

Firefox utilise la propriété textContent conforme au W3C .

Je suppose que Safari et Opera prennent également en charge cette propriété.

Prakash K
la source
2
@Bob Au 22 février 2016, ce n'est toujours pas le cas.
krillgar
@krillgar Il est prévu pour Firefox 45, dont la sortie est prévue pour la semaine du 8 mars. Il est déjà dans la version bêta actuelle et est dans aurora depuis un certain temps. Ce que cela signifie pratiquement, c'est que vous pouvez commencer à développer des sites en utilisant innerTextuniquement et vous attendre à ce qu'il fonctionne (avec des bizarreries possibles) sur tous les navigateurs actuels dans un proche avenir, et l'ancien IE également.
Bob
1
FTR: innerTextest profondément différent de textContent, et est en fait très utile (étonnamment à partir d'une bizarrerie présumée IE ...): innerTextessaie de donner une approximation de la façon dont le texte est réellement présenté dans le navigateur, totalement différent textContent, qui retourne à peu près le tag- source de balisage supprimée , ajoutant peu de valeur, ou même des problèmes supplémentaires (comme la perte des limites des mots).
Sz.
innerText n'est toujours pas pris en charge en 2019 sur la version 64.
Tony Dong
285

Mise à jour : j'ai écrit un article de blog détaillant bien mieux toutes les différences .


Firefox utilise le standard W3C Node::textContent, mais son comportement diffère "légèrement" de celui du propriétaire de MSHTML innerText(copié également par Opera il y a quelque temps, parmi des dizaines d'autres fonctionnalités MSHTML).

Tout d'abord, la textContentreprésentation des espaces est différente d' innerTextune. Deuxièmement, et plus important encore, textContent inclut tout le contenu des balises SCRIPT , contrairement à innerText.

Juste pour rendre les choses plus divertissantes, Opera - en plus d'implémenter la norme textContent- a décidé d'ajouter également MSHTML, innerText mais l'a changé pour agir commetextContent - c'est-à-dire, y compris le contenu SCRIPT (en fait, textContentet innerTextdans Opera semble produire des résultats identiques, probablement simplement aliasés les uns aux autres) .

textContentfait partie de l' Nodeinterface, tandis que innerTextfait partie de HTMLElement. Cela signifie, par exemple, que vous pouvez "récupérer" textContentmais pas à innerTextpartir de nœuds de texte:

var el = document.createElement('p');
var textNode = document.createTextNode('x');

el.textContent; // ""
el.innerText; // ""

textNode.textContent; // "x"
textNode.innerText; // undefined

Enfin, Safari 2.x a également une innerTextimplémentation de buggy . Dans Safari, ne innerTextfonctionne correctement que si un élément n'est ni caché (via style.display == "none") ni orphelin du document. Sinon, innerTextrésulte en une chaîne vide.

Je jouais avec l' textContentabstraction (pour contourner ces lacunes), mais cela s'est avéré assez complexe .

Le mieux est de définir d'abord vos besoins exacts et de suivre à partir de là. Il est souvent possible de simplement retirer les balises innerHTMLd'un élément, plutôt que de traiter toutes les textContent/ innerTextdéviations possibles .

Une autre possibilité, bien sûr, consiste à parcourir l'arborescence DOM et à collecter les nœuds de texte de manière récursive.

kangax
la source
35
Chrome prend également en charge innerText, il semble donc que Firefox soit le seul navigateur majeur à ne PAS le prendre en charge. Et IE est le seul navigateur à ne PAS prendre en charge textContent.
mike nelson
7
@mike - Mais il semble qu'il soit 60 fois plus lent à utiliser innerTextdans Chrome. jsperf.com/text-content/3
gblazex
8
textContentest désormais pris en charge dans IE9 +, mais Firefox ne prend toujours pas en charge innerText(bien qu'ils aient ajouté IE-introduit outerHTMLil y a quelques jours à peine).
kangax
1
Pour ceux qui ont encore besoin de prendre en charge IE8, il y a une Node.textContentcale assez complète en cours ici: github.com/usmonster/aight/blob/node-textcontent-shim/js/… (j'espère bientôt être inclus dans aight ).
Noyo
83

Si vous avez seulement besoin de définir le contenu du texte et non de le récupérer, voici une version DOM triviale que vous pouvez utiliser sur n'importe quel navigateur; elle ne nécessite ni l'extension IE innerText ni la propriété DOM Level 3 Core textContent.

function setTextContent(element, text) {
    while (element.firstChild!==null)
        element.removeChild(element.firstChild); // remove all existing content
    element.appendChild(document.createTextNode(text));
}
bobince
la source
À moins que JavaScript n'ait un opérateur "! ==", je pense que cet opérateur sur la deuxième ligne devrait simplement être "! =".
RexE
23
@RexE: JavaScript a un !==opérateur, l'inverse de ===. La comparaison sensible au type utilisée par ===/ !==est généralement préférable aux comparateurs lâches ==/ !=.
bobince
Dans Internet Explorer, cela ne fonctionne pas pour définir le texte des balises de script (je les utilisais pour un modèle). Vous avez défini `scriptTagElement.text = 'mon modèle {{ici}}';
Christopher Tarquini du
J'ai dû réfléchir très dur pour comprendre pourquoi vous avez utilisé la boucle (et je la supprimerais !==nullcomplètement d'ailleurs) au lieu de simplement remplacer la boucle par element.innerHTML=''(ce qui est censé faire exactement le même travail que la boucle, puis je me suis souvenu .. .: tableaux dans (legacy-) IE ... ericvasilik.com/2006/07/code-karma.html Puis-je suggérer d'ajouter une brève description de «l' effet secondaire » caché et presque jamais documenté du createTextNoderemplacement de l'ampli lt et gt à leurs entités de caractère html respectives? Un lien vers son comportement exact serait grand!
GitaarLAB
26

jQuery fournit une .text()méthode qui peut être utilisée dans n'importe quel navigateur. Par exemple:

$('#myElement').text("Foo");
user161433
la source
22

Selon la réponse de Prakash K, Firefox ne prend pas en charge la propriété innerText. Vous pouvez donc simplement tester si l'agent utilisateur prend en charge cette propriété et procéder en conséquence comme ci-dessous:

function changeText(elem, changeVal) {
    if (typeof elem.textContent !== "undefined") {
        elem.textContent = changeVal;
    } else {
        elem.innerText = changeVal;
    }
}
rism
la source
2
'textContent' dans elem serait plus simple
Jamie Pate
if (elem.textContent! = null) serait aussi plus facile!
Elmue
14

Une ligne très simple de Javascript peut obtenir le texte "sans taggy" dans tous les principaux navigateurs ...

var myElement = document.getElementById('anyElementId');
var myText = (myElement.innerText || myElement.textContent);
Dave
la source
2
Il y a un problème avec celui-ci (au moins dans IE8): si innerText est une chaîne vide et textContent n'est pas défini, alors (myElement.innerText || myElement.textContent) devient indéfini.
Magnus
1
En plus du bogue noté par @Magnus, il convient également de noter qu'il existe des différences significatives dans la manière textContentet le innerTextsignalement des espaces blancs qui peuvent être importants pour certains cas d'utilisation.
Mark Amery
2
Ajoutez simplement un autre ||, c'est- var myText = (myElement.innerText || myElement.textContent || "") ;à- dire: pour surmonter la valeur indéfinie.
PeterM
6

Notez que la Element::innerTextpropriété ne contiendra pas le texte qui a été masqué par le style CSS "display:none " dans Google Chrome (ainsi, il supprimera le contenu masqué par d'autres techniques CSS (y compris la taille de police: 0, la couleur: transparent et quelques autres effets similaires qui empêchent le texte d'être rendu de manière visible).

D'autres propriétés CSS sont également prises en compte:

  • D'abord, le style "display:" des éléments internes est analysé pour déterminer s'il délimite un contenu de bloc (tel que "display: block" qui est la valeur par défaut des éléments de bloc HTML dans la feuille de style intégrée du navigateur, et dont le comportement n'a pas été remplacé par votre propre style CSS); si c'est le cas, une nouvelle ligne sera insérée dans la valeur de la propriété innerText. Cela ne se produira pas avec la propriété textContent.
  • Les propriétés CSS qui génèrent du contenu en ligne seront également prises en compte: par exemple, l'élément en ligne <br \>qui génère une nouvelle ligne en ligne générera également une nouvelle ligne dans la valeur de innerText.
  • Le style "display: inline" n'entraîne aucun retour à la ligne dans textContent ou innerText.
  • Le style "display: table" génère des sauts de ligne autour du tableau et entre les lignes du tableau, mais "display: table-cell" générera un caractère de tabulation.
  • La propriété "position: absolue" (utilisée avec display: block ou display: inline, cela n'a pas d'importance) provoquera également l'insertion d'un saut de ligne.
  • Certains navigateurs incluront également une seule séparation d'espace entre les travées

Mais Element::textContentcontiendra toujours TOUS les contenus des éléments de texte internes indépendamment du CSS appliqué même s'ils sont invisibles. Et aucune nouvelle ligne ni aucun espace supplémentaire ne sera généré dans textContent, qui ignore simplement tous les styles et la structure et les types en ligne / bloc ou positionnés des éléments internes.

Une opération de copier / coller utilisant la sélection de la souris supprimera le texte caché au format de texte brut qui est placé dans le presse-papiers, de sorte qu'il ne contiendra pas tout dans le textContent, mais seulement ce qu'il contient innerText(après la génération d'espaces / de nouvelle ligne comme ci-dessus) .

Les deux propriétés sont ensuite prises en charge dans Google Chrome, mais leur contenu peut alors être différent. Les navigateurs plus anciens incluaient toujours dans innetText tout comme ce que textContent contient maintenant (mais leur comportement par rapport à la génération des espaces blancs / nouvelles lignes était incohérent).

jQuery résoudra ces incohérences entre les navigateurs en utilisant la méthode ".text ()" ajoutée aux éléments analysés qu'elle renvoie via une requête $ (). En interne, il résout les difficultés en examinant le DOM HTML, en travaillant uniquement avec le niveau "nœud". Ainsi, il renverra quelque chose ressemblant davantage à textContent standard.

La mise en garde est que cette méthode jQuery n'insérera pas d'espaces supplémentaires ou de sauts de ligne qui peuvent être visibles à l'écran en raison de sous-éléments (comme <br />) du contenu.

Si vous concevez des scripts pour l'accessibilité et que votre feuille de style est analysée pour un rendu non sonore, comme les plug-ins utilisés pour communiquer avec un lecteur braille, cet outil doit utiliser le textContent s'il doit inclure les signes de ponctuation spécifiques qui sont ajoutés dans des plages de style "display: none" et qui sont généralement inclus dans les pages (par exemple pour les exposants / indices), sinon le innerText sera très déroutant pour le lecteur Braille.

Les textes masqués par les astuces CSS sont désormais généralement ignorés par les principaux moteurs de recherche (qui analyseront également le CSS de vos pages HTML et ignoreront également les textes qui ne sont pas de couleurs contrastées en arrière-plan) à l'aide d'un analyseur HTML / CSS et de la propriété DOM "innerText" exactement comme dans les navigateurs visuels modernes (au moins ce contenu invisible ne sera pas indexé donc le texte caché ne peut pas être utilisé comme une astuce pour forcer l'inclusion de certains mots-clés dans la page pour vérifier son contenu); mais ce texte masqué sera toujours affiché dans la page de résultats (si la page était encore qualifiée à partir de l'index pour être incluse dans les résultats), en utilisant la propriété "textContent" au lieu du HTML complet pour supprimer les styles et scripts supplémentaires.

SI vous affectez du texte brut dans l'une de ces deux propriétés, cela remplacera le balisage interne et les styles qui lui sont appliqués (seul l'élément affecté conservera son type, ses attributs et ses styles), de sorte que les deux propriétés contiendront alors le même contenu . Cependant, certains navigateurs n'honoreront plus l'écriture dans innerText et ne vous permettront que d'écraser la propriété textContent (vous ne pouvez pas insérer de balisage HTML lors de l'écriture dans ces propriétés, car les caractères spéciaux HTML seront correctement encodés à l'aide de références de caractères numériques pour apparaître littéralement , si vous lisez ensuite la innerHTMLpropriété après l'affectation de innerTextou textContent.

verdy_p
la source
1
En fait, "font-size: 0", "color: transparent", "opacity: 0", "text-indent: -9999px", etc. sont tous inclus dans Chrome / WebKit innerText. Dans mes tests, seuls "display: none" et "visibilité: caché" sont ignorés.
kangax
5
myElement.innerText = myElement.textContent = "foo";

Edit (merci à Mark Amery pour le commentaire ci-dessous): Ne le faites que si vous savez hors de tout doute raisonnable qu'aucun code ne s'appuiera sur la vérification de l'existence de ces propriétés, comme (par exemple) jQuery . Mais si vous utilisez jQuery, vous utiliserez probablement la fonction "text" et faire $ ('# myElement'). Text ('foo') comme le montrent certaines autres réponses.

Kwateco
la source
4
-1; C'est une mauvaise idée. Il est extrêmement courant que le code - y compris le code dans des bibliothèques comme jQuery - vérifie l'existence des propriétés innerTextou textContentpour décider laquelle utiliser. En définissant les deux sur une chaîne, vous ferez en sorte que le code d'autres personnes agissant sur l'élément détecte par erreur que le navigateur prend en charge les deux propriétés; par conséquent, ce code est susceptible de mal se comporter.
Mark Amery
JQuery $ ('# myElement'). Val () fonctionne pour plusieurs navigateurs.
Tony Dong
4

innerTexta été ajouté à Firefox et devrait être disponible dans la version FF45: https://bugzilla.mozilla.org/show_bug.cgi?id=264412

Un projet de spécification a été rédigé et devrait être intégré dans le standard de vie HTML à l'avenir: http://rocallahan.github.io/innerText-spec/ , https://github.com/whatwg/html/issues/ 465

Notez qu'actuellement les implémentations de Firefox, Chrome et IE sont toutes incompatibles. À l'avenir, nous pouvons probablement nous attendre à ce que Firefox, Chrome et Edge convergent alors que l'ancien IE reste incompatible.

Voir aussi: https://github.com/whatwg/compat/issues/5

Bob
la source
Existe-t-il un polyfill disponible?
serv-inc
1
@user Cela dépend vraiment de ce dont vous avez besoin. Si vous n'avez pas besoin de prendre en charge les anciennes versions de Firefox et ne vous souciez pas des différences mineures dans la mise en œuvre, utilisez simplement innerText. Si textContentc'est une solution de rechange acceptable et que vous devez prendre en charge l'ancien Fx, utilisez-le (innerText || textContent). Si vous voulez une implémentation identique sur tous les navigateurs, je ne pense pas qu'il existe de polyfill spécifique pour cela, mais certains cadres (par exemple jQuery) peuvent déjà implémenter quelque chose de similaire - reportez-vous aux autres réponses sur cette page.
Bob
1
La fonctionnalité de innerText, c'est-à-dire: le texte visible sur une page, dans Firefox> = 38 (pour un addon) Au moins, les <script>balises doivent être complètement omises. jQuery $('#body').text()n'a pas fonctionné pour moi. Mais comme solution de contournement, innerText || textContentc'est correct. Je vous remercie.
serv-inc
@user Oui, si vous devez prendre en charge Fx 38, cette réponse ne s'applique pas vraiment. Vous devrez vivre avec les limitations / différences de textContentpour l'instant.
Bob
1

Et quelque chose comme ça?

//$elem is the jQuery object passed along.

var $currentText = $elem.context.firstChild.data.toUpperCase();

** J'avais besoin de mettre le mien en majuscule.

Webmaster G
la source
1
Solution de merde; cela ne fonctionne pas si l'élément contient autre chose qu'un seul nœud de texte.
Mark Amery
0

Cela a été mon expérience avec innerText, textContent, innerHTMLet la valeur:

// elem.innerText = changeVal;  // works on ie but not on ff or ch
// elem.setAttribute("innerText", changeVal); // works on ie but not ff or ch
// elem.textContent = changeVal;  // works on ie but not ff or ch
// elem.setAttribute("textContent", changeVal);  // does not work on ie ff or ch
// elem.innerHTML = changeVal;  // ie causes error - doesn't work in ff or ch
// elem.setAttribute("innerHTML", changeVal); //ie causes error doesn't work in ff or ch
   elem.value = changeVal; // works in ie and ff -- see note 2 on ch
// elem.setAttribute("value", changeVal); // ie works; see note 1 on ff and note 2 on ch

ie = internet explorer, ff = firefox, ch = google chrome. note 1: ff fonctionne jusqu'à ce que la valeur soit supprimée avec retour arrière - voir la note de Ray Vega ci-dessus. note 2: fonctionne quelque peu en chrome - après la mise à jour, il reste inchangé, puis vous cliquez loin et cliquez de nouveau dans le champ et la valeur apparaît. Le meilleur du lot est elem.value = changeVal; que je n'ai pas commenté ci-dessus.

Marc
la source
1
est ce juste moi ? ou ignorer complètement la question OP? il a demandé innerText / textContent, et vous parlez principalement des entrées.
Dementic
Cette réponse est très difficile à lire. D'un autre côté, je ne suis pas convaincu que le contenu ait suffisamment de valeur pour mériter de le ranger.
Mark Amery du
-1

Juste republier des commentaires sous le message d'origine. innerHTML fonctionne dans tous les navigateurs. Merci stefita.

myElement.innerHTML = "foo";

Leonid Alzhin
la source
1
-1; innerHTMLn'est pas un remplacement adéquat pour textContent/ innerTextsauf si vous pouvez être certain que le texte que vous attribuez ne contient aucune balise ou autre syntaxe HTML. Pour toutes les données fournies par l'utilisateur, vous n'avez certainement pas cette garantie. Pousser cette approche sans cette mise en garde est dangereux car cela peut entraîner des failles de sécurité XSS . Avec autant d'approches sûres disponibles, il n'y a aucune raison d'envisager celle-ci.
Mark Amery
Mark, ma compréhension est que innerHTML est un moyen normal d'écrire des données dans des éléments html comme div, span, p. Je l'utilise pour traiter les données JSON retournées. C'est aussi dans JQuery ...
Leonid Alzhin
1
Si vous obtenez une chaîne arbitraire à partir d'une réponse JSON et l'affectez à celle d'un élément .innerHTML, votre code est cassé et vous êtes potentiellement vulnérable à XSS. Que se passe-t-il si cette chaîne l'est "<script>alert(1)</script>"?
Mark Amery du
1
@MarkAmery: HTML5 spécifie qu'une <script>balise insérée via innerHTMLne doit pas s'exécuter. Mais cela ne protège pas les anciens navigateurs. De plus, HTML5 innerHTMLne protégerait PAS par exemple "<img src='x' onerror='alert(1)'>".
GitaarLAB
-1

trouvé ceci ici:

<!--[if lte IE 8]>
    <script type="text/javascript">
        if (Object.defineProperty && Object.getOwnPropertyDescriptor &&
            !Object.getOwnPropertyDescriptor(Element.prototype, "textContent").get)
          (function() {
            var innerText = Object.getOwnPropertyDescriptor(Element.prototype, "innerText");
            Object.defineProperty(Element.prototype, "textContent",
              { // It won't work if you just drop in innerText.get
                // and innerText.set or the whole descriptor.
                get : function() {
                  return innerText.get.call(this)
                },
                set : function(x) {
                  return innerText.set.call(this, x)
                }
              }
            );
          })();
    </script>
<![endif]-->
simonarame
la source
Une explication serait bien! De plus, il y a une merde bizarre ici; pourquoi utiliser un commentaire conditionnel pour restreindre l'exécution à IE> = 8, plutôt que de cibler IE 8 uniquement, quand IE> = 9 prend en charge textContentnativement ? Il convient également de noter que depuis innerTextet textContentayant des comportements différents, le code ci-dessus n'est pas une textContentcale fidèle - c'est potentiellement important, mais pas nécessairement évident!
Mark Amery
merci d'avoir signalé la faille, elle était destinée à être IE <= 8
simonarame
-2

Il est également possible d'émuler le innerTextcomportement dans d'autres navigateurs:

 if (((typeof window.HTMLElement) !== "undefined") && ((typeof HTMLElement.prototype.__defineGetter__) !== "undefined")) {
     HTMLElement.prototype.__defineGetter__("innerText", function () {
         if (this.textContent) {
             return this.textContent;
         } else {
             var r = this.ownerDocument.createRange();
             r.selectNodeContents(this);
             return r.toString();
         }
     });
     HTMLElement.prototype.__defineSetter__("innerText", function (str) {
         if (this.textContent) {
             this.textContent = str;
         } else {
             this.innerHTML = str.replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/\n/g, "<br />\n");
         }
     });
 }
DitherSky
la source
Je cherche juste des problèmes du haut de ma tête, le passeur est cassé precar il va doubler les nouvelles lignes. Je soupçonne qu'il y a plus de mal ici.
Mark Amery