„innerText” działa w IE, ale nie w Firefox

289

Mam kod JavaScript, który działa w IE, zawierający następujące elementy:

myElement.innerText = "foo";

Wydaje się jednak, że właściwość „innerText” nie działa w przeglądarce Firefox. Czy jest jakiś odpowiednik Firefoksa? A może istnieje bardziej ogólna właściwość dla wielu przeglądarek, z której można skorzystać?

Promień
źródło
3
Powinno to zrobić myElement.innerHTML = "foo";
stefita,
Spowoduje to zastąpienie WSZYSTKIEGO HTML w obiekcie podaną wartością.
Kucyki OMG,
24
W tym miejscu biblioteki takie jak jQuery ułatwiają życie, ponieważ zajmują się niespójnościami w różnych przeglądarkach, umożliwiając korzystanie ze standardowego frameworka.
Dan Diplo,
Ale i tak może pasować, jeśli nie ma HTML do załatwienia.
Alex Polo
21
Powiedz nam więc, jak korzystać z tej alternatywy dla różnych przeglądarek zamiast po prostu powiedzieć, że jest to możliwe (co nie jest konstruktywne).
SasQ

Odpowiedzi:

249

Firefox używa tekstu zgodnego z W3C właściwości .

Sądzę, że Safari i Opera również obsługują tę właściwość.

Prakash K
źródło
2
@Bob Od 22 lutego 2016 r. Nadal nie jest.
krillgar
@krillgar Planowane jest wydanie Firefoksa 45, którego premiera nastąpi 8 marca. Jest już w bieżącej wersji beta i od pewnego czasu znajduje się w zorzy polarnej. Praktycznie oznacza to, że możesz zacząć tworzyć witryny przy użyciu innerTexttylko i oczekiwać, że będzie działać (z możliwymi dziwactwami) we wszystkich obecnych przeglądarkach w najbliższej przyszłości, a także w starej wersji IE.
Bob
1
FTR: innerTextjest głęboko różny od textContenti faktycznie jest bardzo przydatny (zaskakująco z domniemanego dziwactwa IE ...): innerTextpróbuje podać przybliżenie sposobu, w jaki tekst jest faktycznie prezentowany w przeglądarce, zupełnie inaczej niż textContent, co zwraca tylko znacznik pozbawione źródła znaczników , dodające niewielką wartość, a nawet dodatkowe problemy (takie jak utrata granic słów).
Sz.
innerText nadal nie jest obsługiwany w 2019 roku w wersji 64.
Tony Dong
285

Aktualizacja : Napisałem post na blogu, w którym wszystkie różnice zostały znacznie lepiej opisane.


Firefox używa standardu W3C Node::textContent, ale jego zachowanie „nieznacznie” różni się od własności MSHTML innerText(skopiowanej także przez Operę, jakiś czas temu, spośród kilkudziesięciu innych funkcji MSHTML).

Przede wszystkim textContentreprezentacja białych znaków różni się od innerTextjednego. Po drugie, i co ważniejsze, textContent zawiera całą zawartość znacznika SCRIPT , podczas gdy tekst wewnętrzny nie.

Żeby było bardziej zabawnie, Opera - oprócz implementacji standardu textContent- postanowiła również dodać MSHTML, innerText ale zmieniła go tak, by działał jakotextContent - tj. Włączając zawartość SCRIPT (w rzeczywistości, textContenta innerTextOpera wydaje się dawać identyczne wyniki, prawdopodobnie po prostu alias do siebie) .

textContentjest częścią Nodeinterfejsu, podczas gdy innerTextjest częścią HTMLElement. Oznacza to na przykład, że można „pobierać”, textContentale nie innerTextz węzłów tekstowych:

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

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

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

Wreszcie Safari 2.x ma również błędną innerTextimplementację. W przeglądarce Safari innerTextdziała poprawnie tylko wtedy, gdy element nie jest ukryty (przez style.display == "none") ani osierocony z dokumentu. W przeciwnym razie innerTextpowstanie pusty ciąg.

Bawiłem się textContentabstrakcją (aby obejść te braki), ale okazało się to dość skomplikowane .

Najlepiej jest najpierw zdefiniować dokładne wymagania i zacząć od tego momentu. Często można po prostu usunąć tagi innerHTMLz elementu, zamiast zajmować się wszystkimi możliwymi textContent/innerText odchyleniami.

Inną możliwością jest oczywiście przejście po drzewie DOM i rekurencyjne zbieranie węzłów tekstowych.

kangax
źródło
35
Chrome obsługuje także tekst wewnętrzny, więc wygląda na to, że Firefox jest jedyną przeglądarką, która go NIE obsługuje. I IE jest jedyną przeglądarką, która NIE obsługuje textContent.
Mike Nelson,
7
@mike - Ale wydaje się, że jest 60 razy wolniejszy w użyciu innerTextw Chrome. jsperf.com/text-content/3
gblazex
8
textContentjest teraz obsługiwany w IE9 +, ale Firefox nadal nie obsługuje innerText(chociaż dodali IE wprowadzony outerHTMLzaledwie kilka dni temu).
kangax
1
Dla tych, którzy nadal muszą obsługiwać IE8, jest tu dość kompletny shimNode.textContent : github.com/usmonster/aight/blob/node-textcontent-shim/js/… (mam nadzieję, że wkrótce zostanie włączony do aight ).
Noyo
83

Jeśli potrzebujesz tylko ustawić treść tekstową, a nie pobierać, oto trywialna wersja DOM, której możesz używać w dowolnej przeglądarce; nie wymaga ani rozszerzenia IE innerText, ani właściwości textContent 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));
}
Bobin
źródło
O ile JavaScript nie ma operatora „! ==”, myślę, że operator w drugim wierszu powinien być po prostu „! =”.
RexE,
23
@ RexE: JavaScript ma !==operator, odwrotnie ===. Porównanie czułe na rodzaj używane przez ===/ !==jest zwykle lepsze niż luźne komparatory ==/ !=.
bobince
W Internet Explorerze nie działa to w celu ustawienia tekstu znaczników skryptu (używałem ich jako szablonu). Ustawiłeś `scriptTagElement.text = 'mój szablon {{tutaj}}';
Christopher Tarquini,
Musiałem bardzo ciężko myśleć, aby zrozumieć, dlaczego użyłeś pętli (a tak !==nullna marginesie całkowicie ją odrzuciłbym) zamiast po prostu zastępując ją pętlą element.innerHTML=''(która ma wykonać dokładnie taką samą pracę jak pętla, a potem przypomniałam sobie ... .: tabele w (starszej wersji) IE ... ericvasilik.com/2006/07/code-karma.html Może sugeruję dodanie krótkiego opisu „ukrytego” i prawie nigdy nieudokumentowanego „efektu ubocznego” createTextNodezastąpienia wzmacniacza lt i gt do odpowiednich jednostek znaków HTML? Link do jego dokładnego zachowania byłby wspaniały!
GitaarLAB
26

jQuery zapewnia .text()metodę, której można użyć w dowolnej przeglądarce. Na przykład:

$('#myElement').text("Foo");
użytkownik161433
źródło
22

Zgodnie z odpowiedzią Prakash K Firefox nie obsługuje właściwości innerText. Możesz więc po prostu przetestować, czy agent użytkownika obsługuje tę właściwość i postępować zgodnie z poniższym opisem:

function changeText(elem, changeVal) {
    if (typeof elem.textContent !== "undefined") {
        elem.textContent = changeVal;
    } else {
        elem.innerText = changeVal;
    }
}
rism
źródło
2
'textContent' in elem byłby prostszy
Jamie Pate
if (elem.textContent! = null) też byłoby łatwiejsze!
Elmue,
14

Naprawdę prosta linia Javascript może uzyskać tekst „nie tagowany” we wszystkich głównych przeglądarkach ...

var myElement = document.getElementById('anyElementId');
var myText = (myElement.innerText || myElement.textContent);
Dave
źródło
2
Wystąpił problem z tym (przynajmniej w IE8): Jeśli tekst wewnętrzny jest pustym ciągiem, a tekst nie jest zdefiniowany, to (myElement.innerText || myElement.textContent) staje się niezdefiniowany.
Magnus
1
Oprócz błędu odnotowanego przez @Magnus, warto również zdawać sobie sprawę z faktu, że istnieją znaczne różnice w sposobie textContenti innerTextraportowaniu białych znaków, które mogą mieć znaczenie w niektórych przypadkach użycia.
Mark Amery
2
Po prostu dodaj inną ||, tj .: var myText = (myElement.innerText || myElement.textContent || "") ;aby pokonać nieokreśloną wartość.
PeterM,
6

Pamiętaj, że Element::innerTextwłaściwość nie będzie zawierała tekstu ukrytego za pomocą stylu CSS „display:none ” w Google Chrome (a także usunie treść zamaskowaną przez inne techniki CSS (w tym rozmiar czcionki: 0, kolor: przezroczysty i kilka innych podobnych efektów, które powodują, że tekst nie jest renderowany w żaden widoczny sposób).

Inne właściwości CSS są również brane pod uwagę:

  • Najpierw parsowany jest styl elementów wewnętrznych „display:” w celu ustalenia, czy ogranicza on zawartość bloku (np. „Display: block”, który jest domyślnym elementem bloków HTML w wbudowanym arkuszu stylów przeglądarki i którego zachowanie nie zostało zastąpione przez twój własny styl CSS); jeśli tak, nowy wiersz zostanie wstawiony do wartości właściwości innerText. Nie stanie się tak z właściwością textContent.
  • Rozważone zostaną również właściwości CSS, które generują zawartość wbudowaną: na przykład element wbudowany, <br \>który generuje wbudowaną nową linię, również wygeneruje nową linię w wartości tekstu wewnętrznego.
  • Styl „display: inline” nie powoduje wprowadzenia nowej linii ani w textContent, ani w textText.
  • Styl „display: table” generuje nowe wiersze wokół tabeli i między wierszami tabeli, ale „display: table-cell” wygeneruje znak tabulacji.
  • Właściwość „position: bezwzględna” (używana z display: block lub display: inline, to nie ma znaczenia) spowoduje także wstawienie podziału linii.
  • Niektóre przeglądarki zawierają również pojedynczą separację spacji między zakresami

Ale Element::textContent nadal będzie zawierać WSZYSTKIE treści wewnętrznych elementów tekstowych niezależnie od zastosowanego CSS, nawet jeśli są niewidoczne. W textContent nie będą generowane żadne dodatkowe znaki nowej linii ani białe znaki, co po prostu ignoruje wszystkie style i strukturę oraz typy wewnętrzne / blokowe lub pozycjonowane elementów wewnętrznych.

Operacja kopiowania / wklejania za pomocą zaznaczenia myszą spowoduje usunięcie ukrytego tekstu w formacie zwykłego tekstu, który jest umieszczony w schowku, więc nie będzie zawierał wszystkiego w textContent, ale tylko to, co jest w innerTextśrodku (po wygenerowaniu białych znaków / nowej linii, jak wyżej) .

Obie właściwości są następnie obsługiwane w Google Chrome, ale ich treść może być inna. Starsze przeglądarki nadal zawierały innetText - wszystko to, co obecnie zawiera textContent (ale ich zachowanie w stosunku do generowania białych znaków / nowych linii było niespójne).

jQuery rozwiąże te niespójności między przeglądarkami za pomocą metody „.text ()” dodanej do przeanalizowanych elementów, które zwraca poprzez zapytanie $ (). Wewnętrznie rozwiązuje to problemy, zaglądając do HTML DOM, pracując tylko z poziomem „węzła”. Zwróci więc coś bardziej przypominającego standardową zawartość tekstową.

Zastrzeżenie polega na tym, że ta metoda jQuery nie wstawi żadnych dodatkowych spacji ani podziałów linii, które mogą być widoczne na ekranie z powodu podelementów (jak <br />) zawartości.

Jeśli zaprojektujesz niektóre skrypty dla ułatwienia dostępu, a arkusz stylów zostanie przeanalizowany pod kątem renderowania nie-dźwiękowego, na przykład wtyczek używanych do komunikacji z czytnikiem brajlowskim, to narzędzie powinno używać textContent, jeśli musi zawierać określone znaki interpunkcyjne dodane w rozpiętościach z „display: none” i które zazwyczaj są zawarte na stronach (na przykład dla indeksów górnych / dolnych), w przeciwnym razie tekst wewnętrzny będzie bardzo mylący dla czytnika brajlowskiego.

Teksty ukryte przez sztuczki CSS są teraz zwykle ignorowane przez główne wyszukiwarki (które będą również analizować CSS twoich stron HTML, a także będą ignorować teksty, które nie mają kontrastowych kolorów w tle) za pomocą parsera HTML / CSS i właściwości DOM „innerText” dokładnie tak, jak we współczesnych przeglądarkach wizualnych (przynajmniej ta niewidzialna treść nie będzie indeksowana, więc ukryty tekst nie może być użyty jako sztuczka wymuszająca włączenie niektórych słów kluczowych na stronę w celu sprawdzenia jej zawartości); ale ten ukryty tekst będzie nadal wyświetlany na stronie wyników (jeśli strona nadal kwalifikowała się z indeksu do uwzględnienia w wynikach), używając właściwości „textContent” zamiast pełnego HTML do usunięcia dodatkowych stylów i skryptów.

JEŻELI przypiszesz jakiś tekst w dowolnej z tych dwóch właściwości, spowoduje to zastąpienie wewnętrznego znacznika i stylów zastosowanych do niego (tylko przypisany element zachowa swój typ, atrybuty i style), więc obie właściwości będą wówczas zawierać tę samą treść . Jednak niektóre przeglądarki nie będą już honorować zapisu do innerText i pozwolą tylko nadpisać właściwość textContent (nie można wstawiać znaczników HTML podczas pisania do tych właściwości, ponieważ znaki specjalne HTML będą poprawnie kodowane przy użyciu odniesień znaków numerycznych, aby pojawiały się dosłownie , jeśli następnie przeczytasz innerHTMLwłaściwość po przypisaniu innerTextlub textContent.

verdy_p
źródło
1
W rzeczywistości „Chrome-WebKit” zawiera „rozmiar czcionki: 0”, „kolor: przezroczysty”, „krycie: 0”, „wcięcie tekstu: -9999px” itp innerText. W moich testach ignorowane są tylko „display: none” i „visibility: hidden”.
kangax
5
myElement.innerText = myElement.textContent = "foo";

Edycja (dzięki Mark Amery za komentarz poniżej): Zrób to w ten sposób tylko wtedy, gdy wiesz ponad wszelką wątpliwość, że żaden kod nie będzie polegał na sprawdzeniu istnienia tych właściwości, jak (na przykład) jQuery . Ale jeśli używasz jQuery, prawdopodobnie po prostu użyjesz funkcji „tekst” i wykonasz $ ('# myElement'). Text ('foo'), jak pokazują niektóre inne odpowiedzi.

Kwateco
źródło
4
-1; To jest zły pomysł. Niezwykle często zdarza się, że kod - w tym kod w bibliotekach takich jak jQuery - sprawdza istnienie właściwości innerTextlub textContenti decyduje, którego z nich użyć. Ustawiając oba na łańcuch, sprawisz, że kod innej osoby działający na elemencie błędnie wykryje, że przeglądarka obsługuje obie właściwości; w związku z tym kod może źle funkcjonować.
Mark Amery
JQuery $ ('# myElement'). Val () działa w różnych przeglądarkach.
Tony Dong
4

innerTextzostał dodany do przeglądarki Firefox i powinien być dostępny w wersji FF45: https://bugzilla.mozilla.org/show_bug.cgi?id=264412

Wersja robocza została napisana i powinna zostać włączona do standardu HTML w przyszłości: http://rocallahan.github.io/innerText-spec/ , https://github.com/whatwg/html/issues/ 465

Pamiętaj, że obecnie implementacje Firefox, Chrome i IE są niekompatybilne. W przyszłości możemy prawdopodobnie spodziewać się zbieżności Firefoksa, Chrome i Edge, podczas gdy stary IE pozostanie niezgodny.

Zobacz także: https://github.com/whatwg/compat/issues/5

Kok
źródło
Czy jest dostępny polypełniacz?
serv-inc
1
@ użytkownik To naprawdę zależy od tego, czego potrzebujesz. Jeśli nie potrzebujesz obsługi starszych wersji Firefoksa i nie przejmujesz się drobnymi różnicami w implementacji, po prostu użyj innerText. Jeśli textContentjest to akceptowalne rozwiązanie awaryjne i musisz obsługiwać stare Fx, użyj (innerText || textContent). Jeśli chcesz mieć identyczną implementację we wszystkich przeglądarkach, nie sądzę, aby istniała jakaś konkretna polifill do tego, ale niektóre frameworki (np. JQuery) mogą już implementować coś podobnego - zapoznaj się z innymi odpowiedziami na tej stronie.
Bob
1
Funkcjonalność innerText, czyli: widoczny tekst na stronie, w przeglądarce Firefox> = 38 (dla dodatku) Przynajmniej <script>tagi należy całkowicie pominąć. jQuery $('#body').text()nie działało dla mnie. Ale jako obejście innerText || textContentjest w porządku. Dziękuję Ci.
serv-inc
@ użytkownik Tak, jeśli potrzebujesz obsługi Fx 38, ta odpowiedź tak naprawdę nie ma zastosowania. Na razie będziesz musiał żyć z ograniczeniami / różnicami textContent.
Bob
1

Co powiesz na coś takiego?

//$elem is the jQuery object passed along.

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

** Musiałem zrobić moje wielkie litery.

Webmaster G
źródło
1
Bzdury rozwiązanie; nie działa to, jeśli element zawiera coś więcej niż pojedynczy węzeł tekstowy.
Mark Amery
0

To było moje doświadczenie z innerText, textContent, innerHTMLi wartości:

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

tj. Internet Explorer, ff = Firefox, ch = Google Chrome. uwaga 1: ff działa aż do momentu usunięcia wartości z backspace - patrz uwaga Ray Vega powyżej. Uwaga 2: działa nieco w Chrome - po aktualizacji nie ulega zmianie, a następnie klikasz i klikasz z powrotem w pole, a wartość jest wyświetlana. Najlepsze jest to elem.value = changeVal; których nie skomentowałem powyżej.

Marc
źródło
1
czy to tylko ja ? czy może całkowicie ignoruje pytanie OP? poprosił o innerText / textContent, a ty głównie mówisz o danych wejściowych.
Dementyczny
Ta odpowiedź jest bardzo trudna do odczytania. Z drugiej strony nie jestem przekonany, czy treść ma wystarczającą wartość, aby warto ją było uporządkować.
Mark Amery
-1

Odpowiadam tylko na komentarze z oryginalnego postu. innerHTML działa we wszystkich przeglądarkach. Dzięki, Stefan.

myElement.innerHTML = "foo";

Leonid Alzhin
źródło
1
-1; innerHTMLnie jest odpowiednim zamiennikiem textContent/, innerTextchyba że masz pewność, że przypisywany tekst nie zawiera żadnych znaczników ani innej składni HTML. W przypadku jakichkolwiek danych dostarczonych przez użytkownika zdecydowanie nie masz tej gwarancji. Przerzucanie tego podejścia bez tego zastrzeżenia jest niebezpieczne, ponieważ może prowadzić do luk bezpieczeństwa XSS . Przy tak wielu dostępnych bezpiecznych podejściach nie ma powodu, aby nawet rozważać to.
Mark Amery
Mark, rozumiem, że innerHTML jest normalnym sposobem zapisywania danych w elementach HTML takich jak div, span, p. Używam go do przetwarzania zwróconych danych JSON. Jest też w JQuery ...
Leonid Alzhin
1
Jeśli otrzymujesz dowolny ciąg znaków z odpowiedzi JSON i przypisujesz go do elementu .innerHTML, kod jest uszkodzony i jesteś potencjalnie podatny na XSS. Co się stanie, jeśli ten ciąg jest "<script>alert(1)</script>"?
Mark Amery
1
@MarkAmery: HTML5 określa, że <script>tag wstawiony przez innerHTMLnie powinien zostać wykonany. Ale to nie chroni starszych przeglądarek. Ponadto HTML5 innerHTMLNIE chroniłby na przykład "<img src='x' onerror='alert(1)'>".
GitaarLAB,
-1

znalazłem to tutaj:

<!--[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
źródło
Przyjemne byłoby jakieś wyjaśnienie! Poza tym jest tu trochę dziwnego gówna; po co używać komentarza warunkowego, aby ograniczyć wykonywanie do IE> = 8, zamiast celować wyłącznie w IE 8, skoro IE> = 9 obsługuje textContentnatywnie ? Warto również zauważyć, że skoro innerTexti textContentmają różne zachowania, powyższy kod nie jest wiernym textContentoszustwem - jest to potencjalnie ważne, ale niekoniecznie oczywiste!
Mark Amery
dziękuję za zwrócenie uwagi na wadę, miało to być IE <= 8
simonarame
-2

Możliwe jest również emulowanie innerTextzachowania w innych przeglądarkach:

 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
źródło
Po prostu szukając problemów z mojej głowy, seter jest zepsuty przez pres, ponieważ podwoi nowe linie. Podejrzewam, że tutaj jest więcej błędów.
Mark Amery