'innerText' funciona en IE, pero no en Firefox

289

Tengo un código JavaScript que funciona en IE que contiene lo siguiente:

myElement.innerText = "foo";

Sin embargo, parece que la propiedad 'innerText' no funciona en Firefox. ¿Hay algún equivalente de Firefox? ¿O hay una propiedad de navegador cruzado más genérica que se puede usar?

Rayo
fuente
3
Esto debería hacerlo myElement.innerHTML = "foo";
stefita
Eso reemplazará TODO el HTML dentro del objeto con el valor proporcionado.
OMG Ponis
24
Aquí es donde las bibliotecas como jQuery hacen la vida más fácil ya que se encargan de las inconsistencias entre navegadores como este al permitirle usar un marco estándar.
Dan Diplo
Pero aún así podría ser adecuado si no hay HTML para cuidar.
Alex Polo el
21
Díganos cómo usar esta alternativa entre navegadores en lugar de decir que es posible (lo cual no es constructivo).
SasQ

Respuestas:

249

Firefox utiliza la propiedad textContent compatible con W3C .

Supongo que Safari y Opera también admiten esta propiedad.

Prakash K
fuente
2
@Bob A partir del 22 de febrero de 2016 todavía no lo es.
krillgar
@krillgar Está programado para Firefox 45, que se lanzará la semana del 8 de marzo. Ya está en la versión beta actual, y ha estado en aurora por un tiempo. Lo que esto prácticamente significa es que puede comenzar a desarrollar sitios usando innerTextsolo y esperar que funcione (con posibles peculiaridades) en todos los navegadores actuales en un futuro próximo, y también en IE antiguo.
Bob
1
FTR: innerTextes profundamente diferente de textContent, y en realidad es muy útil (sorprendentemente de una presunta peculiaridad de IE ...): innerTextintenta dar una aproximación de cómo se presenta realmente el texto en el navegador, totalmente diferente textContent, lo que devuelve casi la etiqueta fuente de marcado despojado , agregando poco valor, o incluso problemas adicionales (como la pérdida de límites de palabras).
Sz.
innerText todavía no es compatible en 2019 en la versión 64.
Tony Dong
285

Actualización : escribí una publicación de blog detallando todas las diferencias mucho mejor.


Firefox usa el estándar W3C Node::textContent, pero su comportamiento difiere "levemente" del del propietario de MSHTML innerText(copiado también por Opera, hace algún tiempo, entre docenas de otras características de MSHTML).

En primer lugar, la textContentrepresentación de espacios en blanco es diferente de innerTextuno. En segundo lugar, y más importante, textContent incluye todo el contenido de la etiqueta SCRIPT , mientras que innerText no.

Solo para hacer las cosas más entretenidas, Opera, además de implementar el estándar textContent, decidió agregar también MSHTML, innerText pero lo cambió para que actuaratextContent , es decir, incluir contenidos SCRIPT (de hecho, textContenty innerTexten Opera parecen producir resultados idénticos, probablemente solo se alias entre sí) .

textContentes parte de la Nodeinterfaz, mientras que innerTextes parte de HTMLElement. Esto, por ejemplo, significa que puede "recuperar" textContentpero no innerTextdesde nodos de texto:

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

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

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

Finalmente, Safari 2.x también tiene una innerTextimplementación con errores . En Safari, innerTextfunciona correctamente solo si un elemento no está oculto (vía style.display == "none") ni huérfano del documento. De lo contrario, innerTextda como resultado una cadena vacía.

Estaba jugando con la textContentabstracción (para solucionar estas deficiencias), pero resultó ser bastante complejo .

Su mejor opción es definir primero sus requisitos exactos y seguir desde allí. A menudo es posible simplemente quitar las etiquetas innerHTMLde un elemento, en lugar de tratar con todas las posibles textContent/ innerTextdesviaciones.

Otra posibilidad, por supuesto, es recorrer el árbol DOM y recopilar nodos de texto de forma recursiva.

kangax
fuente
35
Chrome también admite innerText, por lo que parece que Firefox es el único navegador importante que NO lo admite. E IE es el único navegador que NO admite textContent.
Mike Nelson
77
@mike - Pero parece que es 60 veces más lento de usar innerTexten Chrome. jsperf.com/text-content/3
gblazex
8
textContentahora es compatible con IE9 +, pero Firefox todavía no es compatible innerText(aunque agregaron IE-introducido hace outerHTMLsolo unos días).
kangax
1
Para aquellos que todavía necesitan admitir IE8, hay una Node.textContentcuña bastante completa en progreso aquí: github.com/usmonster/aight/blob/node-textcontent-shim/js/… (espero que pronto se incluya en aight ).
Noyo
83

Si solo necesita configurar el contenido de texto y no recuperarlo, aquí hay una versión DOM trivial que puede usar en cualquier navegador; no requiere la extensión IE innerText o la propiedad 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
fuente
A menos que JavaScript tenga un operador "! ==", creo que ese operador en la segunda línea debería ser "! =".
RexE
23
@RexE: JavaScript tiene un !==operador, el inverso de ===. La comparación sensible al tipo utilizada por ===/ !==generalmente es preferible a los comparadores sueltos ==/ !=.
bobince
En Internet Explorer, esto no funciona para establecer el texto de las etiquetas de script (las estaba usando para una plantilla). Ha configurado `scriptTagElement.text = 'mi plantilla {{aquí}}';
Christopher Tarquini
Tuve que pensar mucho para entender por qué usaste el bucle (y yo lo descartaría !==nullpor completo) en lugar de simplemente reemplazar el bucle con element.innerHTML=''(que está especificado para hacer exactamente el mismo trabajo que el bucle y luego recordé ... .: tablas en (legacy-) IE ... ericvasilik.com/2006/07/code-karma.html ¿Puedo sugerir agregar una breve descripción del ' efecto secundario' 'oculto' y casi nunca documentado de createTextNodereemplazar el amplificador? ? y gt a sus respectivas entidades de caracteres hTML Un enlace a su comportamiento exacto puede ser magnífica!
GitaarLAB
26

jQuery proporciona un .text()método que puede usarse en cualquier navegador. Por ejemplo:

$('#myElement').text("Foo");
usuario161433
fuente
22

Según la respuesta de Prakash K, Firefox no admite la propiedad innerText. Por lo tanto, simplemente puede probar si el agente de usuario admite esta propiedad y proceder en consecuencia de la siguiente manera:

function changeText(elem, changeVal) {
    if (typeof elem.textContent !== "undefined") {
        elem.textContent = changeVal;
    } else {
        elem.innerText = changeVal;
    }
}
rismo
fuente
2
'textContent' en elem sería más simple
Jamie Pate
¡si (elem.textContent! = null) también sería más fácil!
Elmue
14

Una línea realmente simple de Javascript puede obtener el texto "no etiquetado" en todos los navegadores principales ...

var myElement = document.getElementById('anyElementId');
var myText = (myElement.innerText || myElement.textContent);
Dave
fuente
2
Hay un problema con eso (al menos en IE8): si innerText es una cadena vacía y textContent no está definido, entonces (myElement.innerText || myElement.textContent) queda indefinido.
Magnus
1
Además del error observado por @Magnus, también vale la pena tener en cuenta el hecho de que existen diferencias significativas en cómo textContenty cómo innerTextinformar espacios en blanco que pueden ser importantes para algunos casos de uso.
Mark Amery
2
Simplemente agregue otro ||, es decir: var myText = (myElement.innerText || myElement.textContent || "") ;para superar el valor indefinido.
PeterM
6

Tenga en cuenta que la Element::innerTextpropiedad no contendrá el texto que ha estado oculto por el estilo CSS " display:none" en Google Chrome (y también eliminará el contenido que ha sido enmascarado por otras técnicas de CSS (incluido el tamaño de fuente: 0, color: transparente y algunos otros efectos similares que hacen que el texto no se represente de manera visible).

También se consideran otras propiedades CSS:

  • Primero, el estilo "display:" de los elementos internos se analiza para determinar si delimita un contenido de bloque (como "display: block", que es el valor predeterminado de los elementos de bloque HTML en la hoja de estilo integrada del navegador, y cuyo comportamiento no ha sido anulado por tu propio estilo CSS); Si es así, se insertará una nueva línea en el valor de la propiedad innerText. Esto no sucederá con la propiedad textContent.
  • También se considerarán las propiedades CSS que generan contenidos en línea: por ejemplo, el elemento en línea <br \>que genera una nueva línea en línea también generará una nueva línea en el valor de innerText.
  • El estilo "display: inline" no causa nueva línea en textContent o innerText.
  • El estilo "display: table" genera nuevas líneas alrededor de la tabla y entre las filas de la tabla, pero "display: table-cell" generará un carácter de tabulación.
  • La propiedad "posición: absoluta" (utilizada con display: block o display: inline, no importa) también hará que se inserte un salto de línea.
  • Algunos navegadores también incluirán una separación de espacio único entre tramos

Pero Element::textContentaún contendrá TODOS los contenidos de elementos de texto interno independientemente del CSS aplicado, incluso si son invisibles. Y no se generarán nuevas líneas o espacios en blanco adicionales en textContent, que simplemente ignora todos los estilos y la estructura y los tipos de elementos internos en línea / bloqueados o posicionados.

Una operación de copiar / pegar usando la selección del mouse descartará el texto oculto en el formato de texto sin formato que se coloca en el portapapeles, por lo que no contendrá todo lo que contiene textContent, sino solo lo que está dentro innerText(después de la generación de espacios en blanco / nueva línea como se indicó anteriormente) .

Ambas propiedades son compatibles con Google Chrome, pero su contenido puede ser diferente. Los navegadores más antiguos todavía se incluían en innetText, todo lo que ahora contiene textContent (pero su comportamiento en relación con la generación de espacios en blanco / líneas nuevas era inconsistente).

jQuery resolverá estas inconsistencias entre los navegadores utilizando el método ".text ()" agregado a los elementos analizados que devuelve mediante una consulta $ (). Internamente, resuelve las dificultades al mirar el DOM HTML, trabajando solo con el nivel de "nodo". Por lo tanto, devolverá algo que se parece más al contenido de texto estándar.

La advertencia es que este método jQuery no insertará espacios adicionales o saltos de línea que puedan ser visibles en la pantalla causados ​​por subelementos (como <br />) del contenido.

Si diseña algunos scripts para la accesibilidad y su hoja de estilo se analiza para la representación no auditiva, como los complementos utilizados para comunicarse con un lector Braille, esta herramienta debe usar el contenido de texto si debe incluir los signos de puntuación específicos que se agregan en tramos con estilo "display: none" y que normalmente se incluyen en las páginas (por ejemplo, para superíndices / subíndices), de lo contrario, el texto interno será muy confuso para el lector Braille.

Los textos ocultos por los trucos CSS ahora son generalmente ignorados por los principales motores de búsqueda (que también analizarán el CSS de sus páginas HTML, y también ignorarán los textos que no tienen colores contrastantes en el fondo) usando un analizador HTML / CSS y la propiedad DOM "innerText" exactamente como en los navegadores visuales modernos (al menos este contenido invisible no se indexará, por lo que el texto oculto no se puede usar como un truco para forzar la inclusión de algunas palabras clave en la página para verificar su contenido); pero este texto oculto todavía se mostrará en la página de resultados (si la página aún estaba calificada del índice para ser incluida en los resultados), utilizando la propiedad "textContent" en lugar del HTML completo para eliminar los estilos y scripts adicionales.

SI asigna texto sin formato en cualquiera de estas dos propiedades, esto sobrescribirá el marcado interno y los estilos aplicados (solo el elemento asignado mantendrá su tipo, atributos y estilos), por lo que ambas propiedades contendrán el mismo contenido . Sin embargo, algunos navegadores ya no respetarán la escritura en innerText, y solo le permitirán sobrescribir la propiedad textContent (no puede insertar marcado HTML al escribir en estas propiedades, ya que los caracteres especiales HTML se codificarán correctamente usando referencias de caracteres numéricos para aparecer literalmente , si luego lee la innerHTMLpropiedad después de la asignación de innerTexto textContent.

verdy_p
fuente
1
En realidad, "tamaño de fuente: 0", "color: transparente", "opacidad: 0", "sangría de texto: -9999px", etc., están incluidos en Chrome / WebKit's innerText. En mis pruebas, solo se ignoran "display: none" y "visibilidad: oculto".
kangax
5
myElement.innerText = myElement.textContent = "foo";

Editar (gracias a Mark Amery por el comentario a continuación): solo hágalo de esta manera si sabe más allá de una duda razonable que ningún código dependerá de verificar la existencia de estas propiedades, como (por ejemplo) jQuery . Pero si está utilizando jQuery, probablemente usaría la función "text" y haría $ ('# myElement'). Text ('foo') como muestran otras respuestas.

Kwateco
fuente
44
-1; esta es una mala idea. Es extremadamente común que el código, incluido el código en bibliotecas como jQuery , verifique la existencia de las propiedades innerTexto textContentpara decidir cuál usar. Al establecer ambos en una cadena, hará que el código de otras personas que actúa sobre el elemento detecte por error que el navegador admite ambas propiedades; en consecuencia, ese código puede comportarse mal.
Mark Amery
JQuery $ ('# myElement'). Val () funciona para el navegador cruzado.
Tony Dong
4

innerTextse ha agregado a Firefox y debería estar disponible en la versión FF45: https://bugzilla.mozilla.org/show_bug.cgi?id=264412

Se ha escrito un borrador de especificaciones y se espera que se incorpore al estándar de vida HTML en el futuro: http://rocallahan.github.io/innerText-spec/ , https://github.com/whatwg/html/issues/ 465

Tenga en cuenta que actualmente las implementaciones de Firefox, Chrome e IE son incompatibles. En el futuro, probablemente podamos esperar que Firefox, Chrome y Edge converjan mientras que el antiguo IE sigue siendo incompatible.

Ver también: https://github.com/whatwg/compat/issues/5

Beto
fuente
¿Hay un polyfill disponible?
serv-inc
1
@user Realmente depende de lo que necesites. Si no necesita admitir versiones anteriores de Firefox y no le importan las pequeñas diferencias en la implementación, simplemente utilícelo innerText. Si textContentes un respaldo aceptable y necesita admitir Fx antiguo, entonces úselo (innerText || textContent). Si desea una implementación idéntica en todos los navegadores, no creo que haya ningún polyfill específico para esto, pero algunos marcos (por ejemplo, jQuery) ya podrían implementar algo similar; consulte las otras respuestas en esta página.
Bob
1
La funcionalidad de innerText, es decir: el texto visible en una página, en Firefox> = 38 (para un complemento) Al menos, las <script>etiquetas deben omitirse por completo. jQuery $('#body').text()no funcionó para mí. Pero como solución alternativa innerText || textContentestá bien. Gracias.
serv-inc
@user Sí, si necesita admitir Fx 38, esta respuesta realmente no se aplica. Tendrás que vivir con las limitaciones / diferencias de textContentpor ahora.
Bob
1

¿Qué tal algo como esto?

//$elem is the jQuery object passed along.

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

** Necesitaba poner el mío en mayúscula.

Webmaster G
fuente
1
Solución de mierda; esto no funciona si el elemento contiene algo más que un solo nodo de texto.
Mark Amery
0

Esta ha sido mi experiencia con innerText, textContent, innerHTML, y el valor:

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

es decir, Internet Explorer, ff = firefox, ch = google chrome. nota 1: ff funciona hasta que se elimine el valor con retroceso - vea la nota de Ray Vega arriba. nota 2: funciona un poco en Chrome: después de la actualización no cambia, luego hace clic y vuelve a hacer clic en el campo y aparece el valor. Lo mejor del lote es elem.value = changeVal; que no comenté arriba.

Bagazo
fuente
1
se trata sólo de mí ? o ignoramos abosolutly la pregunta de OP? preguntó por innerText / textContent, y estás hablando principalmente de entradas.
Demencia el
Esta respuesta es muy difícil de leer. Por otro lado, no estoy convencido de que el contenido tenga el valor suficiente para que valga la pena ordenarlo.
Mark Amery
-1

Solo volviendo a publicar los comentarios debajo de la publicación original. innerHTML funciona en todos los navegadores. Gracias stefita

myElement.innerHTML = "foo";

Leonid Alzhin
fuente
1
-1; innerHTMLno es un reemplazo adecuado para textContent/ a innerTextmenos que pueda estar seguro de que el texto que está asignando no contiene ninguna etiqueta u otra sintaxis HTML. Para cualquier información proporcionada por el usuario, definitivamente no tiene esa garantía. Impulsar este enfoque sin esa advertencia es peligroso dado que puede conducir a agujeros de seguridad XSS . Con tantos enfoques seguros disponibles, no hay razón para considerar este.
Mark Amery
Mark, entiendo que innerHTML es una forma normal de escribir datos en elementos html como div, span, p. Lo uso para procesar datos JSON devueltos. También está en JQuery ...
Leonid Alzhin
1
Si obtiene una cadena arbitraria de una respuesta JSON y la asigna a un elemento .innerHTML, su código se rompe y es potencialmente vulnerable a XSS. ¿Qué pasa si esa cadena es "<script>alert(1)</script>"?
Mark Amery
1
@MarkAmery: HTML5 especifica que una <script>etiqueta insertada a través de innerHTMLno debe ejecutarse. Pero eso no protege a los navegadores más antiguos. Además, HTML5 innerHTMLNO salvaguardaría, por ejemplo "<img src='x' onerror='alert(1)'>".
GitaarLAB
-1

encontré esto aquí:

<!--[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
fuente
¡Alguna explicación sería buena! Además, hay algo raro aquí; ¿por qué usar un comentario condicional para restringir la ejecución a IE> = 8, en lugar de apuntar únicamente a IE 8, cuando IE> = 9 admite de textContentforma nativa ? Es también digno de mención que desde innerTexty textContenttener diferentes comportamientos, el código anterior no es un fiel textContentcuña - esto es potencialmente importante, pero no necesariamente obvio!
Mark Amery
gracias por señalar la falla, estaba destinado a ser IE <= 8
simonarame
-2

También es posible emular el innerTextcomportamiento en otros navegadores:

 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
fuente
Solo buscando problemas en la parte superior de mi cabeza, el setter está roto por pres ya que duplicará las nuevas líneas. Sospecho que hay más errores aquí.
Mark Amery