'innerText' funziona in IE, ma non in Firefox


289

Ho del codice JavaScript che funziona in IE contenente quanto segue:

myElement.innerText = "foo";

Tuttavia, sembra che la proprietà 'innerText' non funzioni in Firefox. Esiste un equivalente di Firefox? Oppure esiste una proprietà più generica per browser diversi che può essere utilizzata?


3
Questo dovrebbe farlo myElement.innerHTML = "pippo";
stefita,

Ciò sostituirà TUTTO l'HTML all'interno dell'oggetto con il valore fornito.
OMG Pony il

24
È qui che le biblioteche come jQuery semplificano la vita in quanto si occupano delle incoerenze tra browser come questa consentendo di utilizzare un framework standard.
Dan Diplo,

Ma potrebbe comunque adattarsi se non c'è HTML di cui occuparsi.
Alex Polo,

21
Quindi dicci come utilizzare questa alternativa tra browser invece di dire semplicemente che è possibile (che non è costruttivo).
SasQ,

Risposte:


249

Firefox utilizza la proprietà textContent conforme a W3C .

Immagino che Safari e Opera supportino anche questa proprietà.



2
@Bob Al 22 febbraio 2016 non lo è ancora.
Krillgar,

@krillgar È previsto per Firefox 45, che dovrebbe essere rilasciato la settimana dell'8 marzo. È già nell'attuale versione beta ed è stato nell'aurora per un po '. Ciò significa praticamente che puoi iniziare a sviluppare siti usando innerTextsolo e aspettarti che funzioni (con possibili stranezze) su tutti i browser attuali nel prossimo futuro, e anche su vecchio IE.
Bob,

1
FTR: innerTextè profondamente diverso da textContent, e in realtà è molto utile (sorprendentemente da una presunta stranezza di IE ...): innerTextcerca di dare un'approssimazione di come il testo è effettivamente presentato nel browser, totalmente diverso textContent, che restituisce solo il tag- sorgente di markup spogliata , aggiungendo poco valore o persino problemi extra (come la perdita dei confini delle parole).
Sz.

innerText non supporta ancora nel 2019 sulla versione 64.
Tony Dong

285

Aggiornamento : ho scritto un post sul blog che descrive in modo molto migliore tutte le differenze .


Firefox utilizza lo standard W3C Node::textContent, ma il suo comportamento differisce "leggermente" da quello del proprietario di MSHTML innerText(copiato anche da Opera, qualche tempo fa, tra dozzine di altre funzionalità MSHTML).

Prima di tutto, la textContentrappresentazione degli spazi bianchi è diversa da innerTextuna. In secondo luogo, e soprattutto, textContent include tutto il contenuto dei tag SCRIPT , mentre innerText no.

Solo per rendere le cose più divertenti, Opera - oltre a implementare lo standard textContent- ha deciso di aggiungere anche MSHTML innerText ma lo ha cambiato in modo da comportarsi cometextContent - cioè includendo i contenuti SCRIPT (in effetti, textContente innerTextin Opera sembrano produrre risultati identici, probabilmente essendo solo uno con l'altro) .

textContentfa parte Nodedell'interfaccia, mentre innerTextfa parte di HTMLElement. Questo, ad esempio, significa che puoi "recuperare" textContentma non innerTextdai nodi di testo:

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

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

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

Infine, Safari 2.x ha anche innerTextun'implementazione errata . In Safari, innerTextfunziona correttamente solo se un elemento non è né nascosto (via style.display == "none") né orfano dal documento. Altrimenti, innerTextrisulta in una stringa vuota.

Stavo giocando con l' textContentastrazione (per ovviare a queste carenze), ma si è rivelato piuttosto complesso .

La scommessa migliore è innanzitutto definire i requisiti esatti e seguire da lì. Spesso è possibile semplicemente rimuovere i tag da innerHTMLun elemento, anziché occuparsi di tutte le possibili textContent/ innerTextdeviazioni.

Un'altra possibilità, ovviamente, è quella di percorrere l'albero del DOM e raccogliere ricorsivamente nodi di testo.


35
Chrome supporta anche innerText, quindi sembra che Firefox sia l'unico browser principale a NON supportarlo. E IE è l'unico browser a NON supportare textContent.
Mike Nelson

7
@mike - Ma sembra che sia 60 volte più lento da usare innerTextin Chrome. jsperf.com/text-content/3
gblazex,

8
textContentè ora supportato in IE9 +, ma Firefox non supporta ancora innerText(anche se hanno aggiunto IE-introdotto outerHTMLpochi giorni fa).
Kangax,

1
Per coloro che devono ancora supportare IE8, c'è uno Node.textContentshim abbastanza completo in corso qui: github.com/usmonster/aight/blob/node-textcontent-shim/js/… (speriamo presto di essere incluso inight ).
Noyo,


83

Se devi solo impostare il contenuto del testo e non recuperarlo, ecco una banale versione DOM che puoi utilizzare su qualsiasi browser; non richiede né l'estensione IE innerText né la proprietà textContent di DOM Level 3 Core.

function setTextContent(element, text) {
    while (element.firstChild!==null)
        element.removeChild(element.firstChild); // remove all existing content
    element.appendChild(document.createTextNode(text));
}

A meno che JavaScript non abbia un operatore "! ==", penso che l'operatore nella seconda riga dovrebbe essere semplicemente "! =".
RexE,

23
@RexE: JavaScript ha un !==operatore, il contrario di ===. Il confronto sensibile al tipo usato da ===/ !==è generalmente preferibile ai comparatori sciolti ==/ !=.
bobince,

In Internet Explorer questo non funziona per impostare il testo dei tag di script (li stavo usando per un modello). Hai impostato `scriptTagElement.text = 'my template {{here}}';
Christopher Tarquini,

Ho dovuto pensare molto a capire perché hai usato il loop (e comunque lo scarterei !==nullcompletamente) invece di sostituire semplicemente il loop con element.innerHTML=''(che si suppone faccia esattamente lo stesso lavoro del loop e poi mi sono ricordato .. .: tabelle in (legacy-) IE ... ericvasilik.com/2006/07/code-karma.html Potrei suggerire di aggiungere una breve descrizione dell '" effetto collaterale " nascosto e quasi mai documentato della createTextNodesostituzione di amp lt e gt alle rispettive entità personaggio html? Un collegamento al suo comportamento esatto sarebbe grandioso!
GitaarLAB


22

Secondo la risposta di Prakash K, Firefox non supporta la proprietà innerText. Quindi puoi semplicemente verificare se l'agente utente supporta questa proprietà e procedere di conseguenza come di seguito:

function changeText(elem, changeVal) {
    if (typeof elem.textContent !== "undefined") {
        elem.textContent = changeVal;
    } else {
        elem.innerText = changeVal;
    }
}

2
'textContent' in elem sarebbe più semplice
Jamie Pate,

se (elem.textContent! = null) sarebbe anche più facile!
Elmue,

14

Una riga davvero semplice di Javascript può ottenere il testo "non taggy" in tutti i principali browser ...

var myElement = document.getElementById('anyElementId');
var myText = (myElement.innerText || myElement.textContent);

2
C'è un problema con quello (almeno in IE8): Se innerText è una stringa vuota e textContent è indefinito, allora (myElement.innerText || myElement.textContent) diventa indefinito.
Magnus,

1
Oltre al bug notato da @Magnus, vale anche la pena essere consapevoli del fatto che ci sono differenze significative nel modo textContente nel innerTextriferire gli spazi bianchi che possono avere importanza per alcuni casi d'uso.
Mark Amery,

2
Aggiungine semplicemente un altro ||, ovvero: var myText = (myElement.innerText || myElement.textContent || "") ;per superare un valore indefinito.
PeterM,

6

Nota che la Element::innerTextproprietà non conterrà il testo che è stato nascosto dallo stile CSS "display:none " in Google Chrome (inoltre eliminerà il contenuto che è stato mascherato da altre tecniche CSS (inclusi dimensioni del carattere: 0, colore: trasparente e alcuni altri effetti simili che impediscono il rendering del testo in modo visibile).

Altre proprietà CSS sono anche considerate:

  • Innanzitutto viene analizzato lo stile "display:" degli elementi interni per determinare se delimita un contenuto di blocco (come "display: block" che è il valore predefinito degli elementi di blocco HTML nel foglio di stile incorporato del browser e il cui comportamento non è stato sostituito da il tuo stile CSS); in tal caso verrà inserita una nuova riga nel valore della proprietà innerText. Questo non accadrà con la proprietà textContent.
  • Saranno prese in considerazione anche le proprietà CSS che generano contenuti inline: ad esempio l'elemento inline <br \>che genera una nuova riga incorporata genererà anche una nuova riga nel valore di innerText.
  • Lo stile "display: inline" non provoca newline in textContent o innerText.
  • Lo stile "display: table" genera nuove righe attorno alla tabella e tra le righe della tabella, ma "display: table-cell" genererà un carattere di tabulazione.
  • La proprietà "position: absolute" (usata con display: block o display: inline, non importa) farà anche inserire un'interruzione di riga.
  • Alcuni browser includeranno anche una singola separazione dello spazio tra span

Conterrà Element::textContentcomunque TUTTI i contenuti degli elementi di testo interni indipendentemente dal CSS applicato anche se sono invisibili. E nessuna nuova riga o spazio bianco verrà generata in textContent, che ignora semplicemente tutti gli stili e la struttura e i tipi di elementi interni incorporati / in blocco / posizionati.

Un'operazione di copia / incolla utilizzando la selezione del mouse eliminerà il testo nascosto nel formato di testo normale che viene inserito negli appunti, quindi non conterrà tutto textContentciò che è dentro, ma solo ciò che è dentro innerText(dopo la generazione di spazi bianchi / newline come sopra) .

Entrambe le proprietà sono quindi supportate in Google Chrome, ma il loro contenuto potrebbe essere diverso. I browser precedenti includevano ancora in innetText tutto come quello che contiene textContent (ma il loro comportamento in relazione alla generazione di spazi bianchi / newline era incoerente).

jQuery risolverà queste incoerenze tra i browser usando il metodo ".text ()" aggiunto agli elementi analizzati che restituisce tramite una query $ (). Internamente, risolve le difficoltà esaminando il DOM HTML, lavorando solo con il livello "nodo". Quindi restituirà qualcosa che assomiglia di più al textContent standard.

L'avvertenza è che questo metodo jQuery non inserirà spazi aggiuntivi o interruzioni di riga che potrebbero essere visibili sullo schermo a causa di elementi secondari (come <br />) del contenuto.

Se si progettano alcuni script per l'accessibilità e il foglio di stile viene analizzato per il rendering non auricolare, come i plug-in utilizzati per comunicare con un lettore Braille, questo strumento dovrebbe utilizzare il textContent se deve includere i segni di punteggiatura specifici che vengono aggiunti in span in stile con "display: none" e che sono generalmente inclusi nelle pagine (ad esempio per apice / pedice), altrimenti il ​​testo interno sarà molto confuso sul lettore Braille.

I testi nascosti dai trucchi CSS sono ora in genere ignorati dai principali motori di ricerca (che analizzeranno anche il CSS delle tue pagine HTML e ignoreranno anche i testi che non hanno colori contrastanti sullo sfondo) usando un parser HTML / CSS e la proprietà DOM "innerText" esattamente come nei moderni browser visivi (almeno questo contenuto invisibile non verrà indicizzato, quindi il testo nascosto non può essere usato come un trucco per forzare l'inclusione di alcune parole chiave nella pagina per verificarne il contenuto); ma questo testo nascosto verrà visualizzato nella pagina dei risultati (se la pagina era ancora qualificata dall'indice per essere inclusa nei risultati), usando la proprietà "textContent" anziché l'HTML completo per eliminare gli stili e gli script extra.

Se assegni del testo in chiaro in una di queste due proprietà, questo sovrascriverà il markup interno e gli stili ad esso applicati (solo l'elemento assegnato manterrà il suo tipo, attributi e stili), quindi entrambe le proprietà conterranno lo stesso contenuto . Tuttavia, alcuni browser ora non onoreranno più la scrittura su innerText e ti consentiranno solo di sovrascrivere la proprietà textContent (non è possibile inserire markup HTML quando si scrive su queste proprietà, poiché i caratteri speciali HTML verranno codificati correttamente usando riferimenti numerici per apparire letteralmente , se poi leggi la innerHTMLproprietà dopo l'assegnazione di innerTexto textContent.


1
In realtà "dimensione del carattere: 0", "colore: trasparente", "opacità: 0", "testo-indent: -9999px", ecc. Sono tutti inclusi in Chrome / WebKit innerText. Nei miei test, solo "display: none" e "visible: hidden" vengono ignorati.
Kangax,

5
myElement.innerText = myElement.textContent = "foo";

Modifica (grazie a Mark Amery per il commento qui sotto): fallo solo se sai oltre ogni ragionevole dubbio che nessun codice si affiderà al controllo dell'esistenza di queste proprietà, come (ad esempio) fa jQuery . Ma se stai usando jQuery, probabilmente useresti semplicemente la funzione "text" e faresti $ ('# myElement'). Text ('pippo') come mostrano altre risposte.


4
-1; Questa è una cattiva idea. È estremamente comune che il codice, incluso il codice nelle librerie come jQuery , controlli l'esistenza delle proprietà innerTexto textContentper decidere quale utilizzare. Impostando entrambi su una stringa, farai in modo che il codice di altre persone che agiscono sull'elemento rilevi erroneamente che il browser supporta entrambe le proprietà; di conseguenza, tale codice potrebbe comportarsi in modo errato.
Mark Amery,

JQuery $ ('# myElement'). Val () funziona per browser incrociati.
Tony Dong

4

innerTextè stato aggiunto a Firefox e dovrebbe essere disponibile nella versione FF45: https://bugzilla.mozilla.org/show_bug.cgi?id=264412

Una bozza di specifiche è stata scritta e dovrebbe essere incorporata nello standard di vita HTML in futuro: http://rocallahan.github.io/innerText-spec/ , https://github.com/whatwg/html/issues/ 465

Nota che attualmente le implementazioni di Firefox, Chrome e IE sono tutte incompatibili. In futuro, possiamo probabilmente aspettarci che convergano Firefox, Chrome e Edge mentre il vecchio IE rimane incompatibile.

Vedi anche: https://github.com/whatwg/compat/issues/5


È disponibile un polyfill?
serv-inc,

1
@utente Dipende davvero da ciò di cui hai bisogno. Se non hai bisogno di supportare versioni precedenti di Firefox e non ti importa delle differenze minori nell'implementazione, usa semplicemente innerText. Se textContentè un fallback accettabile ed è necessario supportare il vecchio Fx, utilizzare (innerText || textContent). Se desideri un'implementazione identica su tutti i browser, non credo che ci sia un polyfill specifico per questo, ma alcuni framework (ad esempio jQuery) potrebbero già implementare qualcosa di simile - fai riferimento alle altre risposte in questa pagina.
Bob,

1
La funzionalità di innerText, ovvero: il testo visibile su una pagina, in Firefox> = 38 (per un componente aggiuntivo) Almeno, i <script>tag devono essere completamente omessi. jQuery $('#body').text()non ha funzionato per me. Ma come soluzione alternativa innerText || textContentè ok. Grazie.
serv-inc,

@utente Sì, se devi supportare Fx 38, questa risposta non si applica davvero. Dovrai convivere con i limiti / le differenze di textContentper ora.
Bob,

1

Che ne dici di qualcosa del genere?

//$elem is the jQuery object passed along.

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

** Avevo bisogno di rendere il mio maiuscolo.


1
Soluzione di merda; questo non funziona se l'elemento contiene qualcosa di più di un singolo nodo di testo.
Mark Amery,


0

Questa è stata la mia esperienza con innerText, textContent, innerHTMLe il valore:

// 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

cioè = internet explorer, ff = firefox, ch = google chrome. nota 1: ff funziona fino a quando non viene eliminato il valore con backspace - vedere la nota di Ray Vega sopra. nota 2: funziona in qualche modo con Chrome: dopo l'aggiornamento è invariato, quindi fai clic e rientri nel campo e viene visualizzato il valore. Il migliore del lotto è elem.value = changeVal; che non ho commentato sopra.


1
sono solo io ? o ignori assolutamente la domanda di OP? ha chiesto innerText / textContent e per lo più stai parlando di input.
Demenza

Questa risposta è molto difficile da leggere. D'altra parte, non sono convinto che il contenuto abbia abbastanza valore per cui valga la pena riordinarlo.
Mark Amery,

-1

Ripubblicando solo dai commenti sotto il post originale. innerHTML funziona in tutti i browser. Grazie stefita.

myElement.innerHTML = "foo";


1
-1; innerHTMLnon è un sostituto adeguato per textContent/ a innerTextmeno che non si sia certi che il testo che si sta assegnando non contenga tag o altra sintassi HTML. Per tutti i dati forniti dall'utente, sicuramente non hai questa garanzia. Spingere questo approccio senza questo avvertimento è pericoloso dato che può portare a buchi di sicurezza XSS . Con così tanti approcci sicuri disponibili, non c'è motivo di prendere in considerazione anche questo.
Mark Amery,

Mark, la mia comprensione è che innerHTML è un modo normale di scrivere dati su elementi html come div, span, p. Lo uso per elaborare i dati JSON restituiti. È anche in JQuery ...
Leonid Alzhin,

1
Se si ottiene una stringa arbitraria da una risposta JSON e la si assegna a quella di un elemento .innerHTML, il codice viene interrotto e si è potenzialmente vulnerabili a XSS. Cosa succede se quella stringa è "<script>alert(1)</script>"?
Mark Amery,

1
@MarkAmery: HTML5 specifica che un <script>tag inserito tramite innerHTMLnon deve essere eseguito. Ma ciò non protegge i browser più vecchi. Inoltre, HTML5 innerHTMLNON salvaguarderebbe per esempio "<img src='x' onerror='alert(1)'>".
GitaarLAB,

-1

trovato questo qui:

<!--[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]-->

Qualche spiegazione sarebbe buona! Inoltre, c'è qualche strana merda qui; perché utilizzare un commento condizionale per limitare l'esecuzione a IE> = 8, anziché indirizzare esclusivamente IE 8, quando IE> = 9 supporta textContentnativamente ? Vale anche la pena notare che da allora innerTexte textContentcon comportamenti diversi, il codice sopra non è uno textContentshim fedele - questo è potenzialmente importante, ma non necessariamente ovvio!
Mark Amery,

grazie per aver sottolineato il difetto, doveva essere IE <= 8
simonarame

-2

È anche possibile emulare il innerTextcomportamento in altri browser:

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

Sto solo cercando problemi dalla cima della mia testa, il setter è rotto per pres poiché raddoppierà le nuove linee. Ho il sospetto che ci sia più di sbagliato qui.
Mark Amery,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.