'innerText' funciona no IE, mas não no Firefox

289

Eu tenho algum código JavaScript que funciona no IE contendo o seguinte:

myElement.innerText = "foo";

No entanto, parece que a propriedade 'innerText' não funciona no Firefox. Existe algum equivalente do Firefox? Ou existe uma propriedade entre navegadores mais genérica que pode ser usada?

Raio
fonte
3
Isso deve ser feito myElement.innerHTML = "foo";
stefita
Isso substituirá TODO o HTML dentro do objeto pelo valor fornecido.
OMG Ponies
24
É aqui que bibliotecas como o jQuery tornam a vida mais fácil, pois cuidam de inconsistências entre navegadores como essa, permitindo que você use uma estrutura padrão.
31511 Dan Diplo
Mas ainda pode servir se não houver HTML para cuidar.
Alex Polo
21
Diga-nos como usar essa alternativa entre navegadores, em vez de apenas dizer que é possível (o que não é construtivo).
SasQ

Respostas:

249

O Firefox usa a propriedade textContent compatível com W3C .

Eu acho que o Safari e o Opera também suportam essa propriedade.

Prakash K
fonte
2
@Bob Em 22 de fevereiro de 2016 ainda não é.
krillgar
@krillgar Está programado para o Firefox 45, que será lançado na semana de 8 de março. Já está na versão beta atual e está na Aurora há um tempo. Na prática, isso significa que você pode começar a desenvolver sites usando innerTextapenas e esperar que funcione (com possíveis peculiaridades) em todos os navegadores atuais em um futuro próximo e no IE antigo também.
22416 Bob
1
FTR: innerTexté profundamente diferente de textContent, e na verdade é muito útil (surpreendentemente, de uma suposta peculiaridade do IE ...): innerTexttenta fornecer uma aproximação de como o texto é realmente apresentado no navegador, totalmente diferente textContent, que retorna quase a tag- fonte de marcação despojada , agregando pouco valor ou até problemas extras (como a perda dos limites das palavras).
Sz.
innerText ainda não é suportado em 2019 na versão 64.
Tony Dong
285

Atualização : escrevi uma postagem no blog detalhando todas as diferenças muito melhor.


O Firefox usa o padrão W3C Node::textContent, mas seu comportamento difere "levemente" do do proprietário do MSHTML innerText(copiado pelo Opera também, há algum tempo, entre dezenas de outros recursos do MSHTML).

Primeiro de tudo, a textContentrepresentação de espaço em branco é diferente de innerTextum. Segundo, e mais importante, textContent inclui todo o conteúdo da tag SCRIPT , enquanto o innerText não.

Apenas para tornar as coisas mais divertidas, o Opera - além de implementar o padrão textContent- decidiu também adicionar MSHTMLs, innerText mas mudou para atuar comotextContent - isto é, incluindo o conteúdo do SCRIPT (de fato, textContente innerTextno Opera parecem produzir resultados idênticos, provavelmente sendo apenas um alias para o outro) .

textContentfaz parte da Nodeinterface, ao passo que innerTextfaz parte HTMLElement. Isso, por exemplo, significa que você pode "recuperar", textContentmas não innerTextdos nós de texto:

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

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

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

Por fim, o Safari 2.x também possui innerTextimplementação de bugs . No Safari, innerTextfunciona corretamente apenas se um elemento não estiver oculto (via style.display == "none") ou órfão do documento. Caso contrário, innerTextresulta em uma sequência vazia.

Eu estava brincando com textContentabstração (para contornar essas deficiências), mas acabou sendo bastante complexo .

Sua melhor aposta é definir primeiro os requisitos exatos e seguir a partir daí. Muitas vezes, é possível simplesmente remover as tags innerHTMLde um elemento, em vez de lidar com todos os possíveis textContent/ innerTextdesvios.

Outra possibilidade, é claro, é percorrer a árvore DOM e coletar nós de texto recursivamente.

kangax
fonte
35
O Chrome também suporta o innerText, então parece que o Firefox é o único navegador importante a NÃO suportá-lo. E o IE é o único navegador que NÃO suporta textContent.
Mike nelson #
7
@ Mike - Mas parece que é 60x mais lento para usar innerTextno Chrome. jsperf.com/text-content/3
gblazex
8
textContentagora é suportado no IE9 +, mas o Firefox ainda não suporta innerText(embora eles tenham adicionado o IE introduzido outerHTMLapenas alguns dias atrás).
kangax
1
Para aqueles que ainda precisam oferecer suporte ao IE8, há um Node.textContentcalço bastante completo em andamento aqui: github.com/usmonster/aight/blob/node-textcontent-shim/js/… (esperamos que em breve seja incluído no aight ).
Noyo
83

Se você precisa apenas definir o conteúdo do texto e não recuperar, aqui está uma versão trivial do DOM que você pode usar em qualquer navegador; ele não requer a extensão IE innerText ou a propriedade textContent do DOM Nível 3 principal.

function setTextContent(element, text) {
    while (element.firstChild!==null)
        element.removeChild(element.firstChild); // remove all existing content
    element.appendChild(document.createTextNode(text));
}
bobince
fonte
A menos que o JavaScript tenha um operador "! ==", acho que o operador na segunda linha deve ser apenas "! =".
RexE 23/10
23
@RexE: JavaScript tem um !==operador, o inverso de ===. A comparação sensível ao tipo usada por ===/ !==geralmente é preferível aos comparadores frouxos ==/ !=.
bobince
No Internet Explorer, isso não funciona para definir o texto das tags de script (eu as estava usando como modelo). Você configurou `scriptTagElement.text = 'meu modelo {{here}}';
Christopher Tarquini
Eu tive que pensar muito para entender por que você usou o loop (e eu descartaria !==nullcompletamente o caminho) em vez de apenas substituí-lo por element.innerHTML=''(o que é especificado para fazer exatamente o mesmo trabalho que o loop e, então, lembrei-me .. .: tables in (legacy-) IE ... ericvasilik.com/2006/07/code-karma.html Posso sugerir a adição de uma breve descrição do " efeito colateral " oculto e quase nunca documentado da createTextNodesubstituição de amp lt ? e gt às suas respectivas entidades de caracteres html Um link para seu comportamento exato seria grand!
GitaarLAB
26

O jQuery fornece um .text()método que pode ser usado em qualquer navegador. Por exemplo:

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

De acordo com a resposta de Prakash K, o Firefox não suporta a propriedade innerText. Portanto, você pode simplesmente testar se o agente do usuário suporta essa propriedade e proceder conforme a seguir:

function changeText(elem, changeVal) {
    if (typeof elem.textContent !== "undefined") {
        elem.textContent = changeVal;
    } else {
        elem.innerText = changeVal;
    }
}
arriscar
fonte
2
'textContent' em elem seria mais simples
Jamie Pate
se (elem.textContent! = null) também seria mais fácil!
Elmue
14

Uma linha realmente simples de Javascript pode obter o texto "não taggy" em todos os principais navegadores ...

var myElement = document.getElementById('anyElementId');
var myText = (myElement.innerText || myElement.textContent);
Dave
fonte
2
Há um problema com esse (pelo menos no IE8): Se innerText for uma string vazia e textContent for indefinido, (myElement.innerText || myElement.textContent) ficará indefinido.
Magnus
1
Além do bug observado pelo @Magnus, também vale a pena estar ciente do fato de que existem diferenças significativas em como textContente innerTextrelatar espaços em branco que podem ser importantes para alguns casos de uso.
Mark-Augy
2
Basta adicionar outro ||, ou seja: var myText = (myElement.innerText || myElement.textContent || "") ;para superar o valor indefinido.
peterm
6

Observe que a Element::innerTextpropriedade não conterá o texto oculto pelo estilo CSS " display:none" no Google Chrome (também eliminará o conteúdo que foi mascarado por outras técnicas de CSS (incluindo tamanho da fonte: 0, cor: transparente e alguns outros efeitos semelhantes que fazem com que o texto não seja renderizado de maneira visível).

Outras propriedades CSS também são consideradas:

  • Primeiro, o estilo "display:" dos elementos internos é analisado para determinar se ele delimita o conteúdo de um bloco (como "display: block", que é o padrão dos elementos de bloco HTML na folha de estilo interna do navegador e cujo comportamento não foi substituído por seu próprio estilo CSS); Nesse caso, uma nova linha será inserida no valor da propriedade innerText. Isso não acontecerá com a propriedade textContent.
  • As propriedades CSS que geram conteúdo embutido também serão consideradas: por exemplo, o elemento inline <br \>que gera uma nova linha embutida também gerará uma nova linha no valor de innerText.
  • O estilo "display: inline" não causa nova linha em textContent ou innerText.
  • O estilo "display: table" gera novas linhas ao redor da tabela e entre as linhas da tabela, mas "display: table-cell" gera um caractere de tabulação.
  • A propriedade "position: absolute" (usada com display: block ou display: inline, não importa) também fará com que uma quebra de linha seja inserida.
  • Alguns navegadores também incluem uma única separação de espaço entre extensões

Mas Element::textContentainda conterá TODO o conteúdo dos elementos internos do texto independentemente do CSS aplicado, mesmo que sejam invisíveis. E não serão geradas novas linhas ou espaços em branco extras no textContent, que apenas ignora todos os estilos e a estrutura e os tipos de elementos internos embutidos / bloqueados ou posicionados.

Uma operação de copiar / colar usando a seleção do mouse descartará o texto oculto no formato de texto sem formatação colocado na área de transferência, para que não contenha tudo o textContentque estiver dentro, mas apenas o que está dentro innerText(após a geração de espaços em branco / nova linha, como acima) .

Ambas as propriedades são suportadas no Google Chrome, mas seu conteúdo pode ser diferente. Os navegadores mais antigos ainda incluídos no innetText, como tudo o que o conteúdo do conteúdo agora contém (mas o comportamento deles em relação à geração de espaços em branco / novas linhas era inconsistente).

O jQuery resolverá essas inconsistências entre navegadores usando o método ".text ()" adicionado aos elementos analisados ​​que ele retorna por meio de uma consulta $ (). Internamente, ele resolve as dificuldades examinando o HTML DOM, trabalhando apenas com o nível "nó". Portanto, ele retornará algo parecido com o textContent padrão.

A ressalva é que esse método jQuery não inserirá espaços extras ou quebras de linha que possam ser visíveis na tela causadas por subelementos (como <br />) do conteúdo.

Se você projetar alguns scripts para acessibilidade e sua folha de estilo for analisada para renderização não auditiva, como plug-ins usados ​​para se comunicar com um leitor de Braille, essa ferramenta deverá usar o textContent se precisar incluir os sinais de pontuação específicos adicionados em vãos estilizados com "display: none" e que geralmente são incluídos nas páginas (por exemplo, sobrescritos / subscritos); caso contrário, o innerText será muito confuso para o leitor de Braille.

Os textos ocultos pelos truques de CSS agora são normalmente ignorados pelos principais mecanismos de pesquisa (que também analisam o CSS de suas páginas HTML e também ignoram textos que não estão com cores contrastantes no fundo) usando um analisador de HTML / CSS e a propriedade DOM "innerText" exatamente como nos navegadores visuais modernos (pelo menos esse conteúdo invisível não será indexado, portanto, o texto oculto não pode ser usado como um truque para forçar a inclusão de algumas palavras-chave na página para verificar seu conteúdo); mas esse texto oculto ainda será exibido na página de resultados (se a página ainda estiver qualificada no índice para ser incluída nos resultados), usando a propriedade "textContent" em vez do HTML completo para remover os estilos e scripts extras.

Se você atribuir texto sem formatação em qualquer uma dessas duas propriedades, isso substituirá a marcação interna e os estilos aplicados a ela (apenas o elemento atribuído manterá seu tipo, atributos e estilos), portanto, ambas as propriedades conterão o mesmo conteúdo . No entanto, alguns navegadores agora não respeitam mais a gravação em innerText e permitem sobrescrever a propriedade textContent (você não pode inserir a marcação HTML ao gravar nessas propriedades, pois os caracteres especiais HTML serão codificados corretamente usando referências de caracteres numéricos para aparecer literalmente , se você ler a innerHTMLpropriedade após a atribuição de innerTextou textContent.

verdy_p
fonte
1
Na verdade, "tamanho da fonte: 0", "cor: transparente", "opacidade: 0", "recuo do texto: -9999px" etc. etc. estão todos incluídos no Chrome / WebKit innerText. Nos meus testes, apenas "display: none" e "visible: hidden" são ignorados.
kangax
5
myElement.innerText = myElement.textContent = "foo";

Editar (obrigado a Mark Amery pelo comentário abaixo): Faça isso desta maneira apenas se souber, sem sombra de dúvida, que nenhum código dependerá da verificação da existência dessas propriedades, como (por exemplo) o jQuery . Mas se você estiver usando jQuery, provavelmente usaria a função "text" e executaria $ ('# myElement'). Text ('foo'), como mostram outras respostas.

Kwateco
fonte
4
-1; isso é uma péssima ideia. É extremamente comum o código - incluindo código em bibliotecas como jQuery - verificar a existência das propriedades innerTextou textContentpara decidir qual usar. Ao definir ambos como uma sequência, você fará com que o código de outras pessoas que atua no elemento detecte por engano que o navegador suporta as duas propriedades; consequentemente, esse código pode se comportar mal.
Mark Amery
JQuery $ ('# myElement'). Val () funciona para vários navegadores.
Tony Dong
4

innerTextfoi adicionado ao Firefox e deve estar disponível na versão FF45: https://bugzilla.mozilla.org/show_bug.cgi?id=264412

Um rascunho de especificação foi escrito e espera-se que seja incorporado ao padrão de vida em HTML no futuro: http://rocallahan.github.io/innerText-spec/ , https://github.com/whatwg/html/issues/ 465

Observe que atualmente as implementações do Firefox, Chrome e IE são todas incompatíveis. No futuro, provavelmente podemos esperar que o Firefox, Chrome e Edge convergam enquanto o IE antigo permanece incompatível.

Veja também: https://github.com/whatwg/compat/issues/5

Prumo
fonte
Existe um polyfill disponível?
serv-inc
1
@user Realmente depende do que você precisa. Se você não precisa suportar versões mais antigas do Firefox e não se importa com as pequenas diferenças na implementação, basta usar innerText. Se textContentfor um fallback aceitável e você precisar oferecer suporte ao FX antigo, use (innerText || textContent). Se você deseja uma implementação idêntica em todos os navegadores, não acredito que exista um polyfill específico para isso, mas algumas estruturas (por exemplo, jQuery) podem já implementar algo semelhante - consulte as outras respostas nesta página.
Bob
1
A funcionalidade de innerText, isto é: o texto visível em uma página, no Firefox> = 38 (para um complemento) Pelo menos, as <script>tags devem ser completamente omitidas. O jQuery $('#body').text()não funcionou para mim. Mas, como solução alternativa, innerText || textContenttudo bem. Obrigado.
serv-inc
@user Sim, se você precisar dar suporte ao FX 38, essa resposta realmente não se aplica. Você terá que viver com as limitações / diferenças de textContentpor enquanto.
Bob
1

Que tal algo assim?

//$elem is the jQuery object passed along.

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

** Eu precisava fazer a minha maiúscula.

Webmaster G
fonte
1
Solução de porcaria; isso não funciona se o elemento contiver algo além de um único nó de texto.
Mark Amery
0

Esta tem sido a minha experiência com innerText, textContent, innerHTML, e 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

ie = internet explorer, ff = firefox, ch = google chrome. nota 1: ff funciona até que o valor seja excluído com backspace - veja nota de Ray Vega acima. nota 2: funciona um pouco no chrome - após a atualização, ele permanece inalterado e você clica para fora e clica novamente no campo e o valor aparece. O melhor do lote é elem.value = changeVal; que não comentei acima.

Marc
fonte
1
Sou apenas eu ? ou ignora abosolutamente a questão do OP? ele pediu innerText / textContent, e você está falando principalmente de entradas.
Dementic
Esta resposta é muito difícil de ler. Por outro lado, não estou convencido de que o conteúdo tenha valor suficiente para valer a pena arrumá-lo.
Mark Amery
-1

Apenas republicando comentários sob a postagem original. innerHTML funciona em todos os navegadores. Obrigado stefita.

myElement.innerHTML = "foo";

Leonid Alzhin
fonte
1
-1; innerHTMLnão é um substituto adequado para textContent/ a innerTextmenos que você tenha certeza de que o texto que você está atribuindo não contém nenhuma tag ou outra sintaxe HTML. Para quaisquer dados fornecidos pelo usuário, você definitivamente não tem essa garantia. Empurrar essa abordagem sem essa ressalva é perigoso, pois pode levar a falhas de segurança do XSS . Com tantas abordagens seguras disponíveis, não há razão para considerar essa.
Mark Amery
Mark, meu entendimento é que innerHTML é uma maneira normal de gravar dados em elementos html como div, span, p. Eu o uso para processar dados JSON retornados. É em JQuery, também ...
Leonid Alzhin
1
Se você obtiver uma sequência arbitrária de uma resposta JSON e a atribuir a um elemento .innerHTML, seu código será quebrado e você estará potencialmente vulnerável ao XSS. O que acontece se essa string for "<script>alert(1)</script>"?
Mark Amery
1
@MarkAmery: HTML5 especifica que uma <script>tag inserida via innerHTMLnão deve ser executada. Mas isso não protege navegadores antigos. Além disso, o HTML5 innerHTMLNÃO salvaguardaria, por exemplo "<img src='x' onerror='alert(1)'>".
GitaarLAB
-1

encontrou isso aqui:

<!--[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
fonte
Alguma explicação seria legal! Além disso, há algumas coisas estranhas aqui; por que usar um comentário condicional para restringir a execução ao IE> = 8, em vez de direcionar apenas o IE 8, quando o IE> = 9 oferece suporte textContentnativo ? Também vale a pena notar que, uma vez que innerTexte textContentcom comportamentos diferentes, o código acima não é um textContentcalço fiel - isso é potencialmente importante, mas não necessariamente óbvio!
Mark Amery
obrigado por apontar a falha, que se destina a ser IE <= 8
simonarame
-2

Também é possível emular o innerTextcomportamento em outros 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
fonte
Apenas procurando problemas em cima da minha cabeça, o levantador está quebrado por pres, pois duplicará as novas linhas. Eu suspeito que há mais errado aqui.
Mark Amery