«innerText» работает в IE, но не в Firefox


289

У меня есть некоторый код JavaScript, который работает в IE, содержащий следующее:

myElement.innerText = "foo";

Однако, похоже, что свойство «innerText» не работает в Firefox. Есть ли какой-нибудь аналог Firefox? Или есть более общее свойство кросс-браузера, которое можно использовать?


3
Это должно сделать это myElement.innerHTML = "foo";
— Стефита

Это заменит ВСЕ HTML в объекте с предоставленным значением.
— OMG Ponies

24
Именно здесь такие библиотеки, как jQuery, облегчают жизнь, поскольку они заботятся о кросс-браузерных несоответствиях, подобных этой, позволяя вам использовать стандартную среду.
— Дэн Диплом

Но все еще может подойти, если нет HTML, чтобы заботиться.
— Алекс Поло

21
Итак, расскажите нам, как использовать эту кросс-браузерную альтернативу вместо того, чтобы просто сказать, что это возможно (что не конструктивно).
— SasQ

Ответы:


249

Firefox использует W3C-совместимое свойство textContent .

Я думаю, Safari и Opera также поддерживают это свойство.



2
@Bob По состоянию на 22 февраля 2016 года все еще нет.
— крильгар

@krillgar Это запланировано на Firefox 45, который должен выйти на неделе 8 марта. Это уже в текущей бета-версии, и было в Авроре некоторое время. Практически это означает, что вы можете приступить к разработке сайтов, используя innerTextтолько и ожидать, что он будет работать (с возможными причудами) во всех текущих браузерах в ближайшем будущем, а также в старом IE.
— Боб

1
FTR: innerTextэто глубоко отличается от textContent, и на самом деле очень полезно ( на удивлении от предполагаемого IE причуды ...) innerTextпытается дать приближение того , как текст на самом деле представлен в браузере, совершенно не похож textContent, что возвращается только о tag- лишенный источник разметки , добавление небольшого значения или даже дополнительные проблемы (такие как потеря границ слова).
— СЗ


285

Обновление : я написал сообщение в блоге, детализирующее все различия намного лучше.


Firefox использует стандарт W3C Node::textContent, но его поведение "немного" отличается от поведения проприетарного MSHTML innerText(также скопированного Opera некоторое время назад среди десятков других функций MSHTML).

Прежде всего, textContentпредставление пробелов отличается от innerTextодного. Во-вторых, и что более важно, textContent включает в себя все содержимое тега SCRIPT , в то время как innerText нет.

Просто чтобы сделать вещи более интересными, Opera - помимо реализации стандарта textContent- решила также добавить MSHTML, innerText но изменила его так, чтобы он действовал какtextContent - то есть включая содержимое SCRIPT (фактически, textContentи innerTextв Opera, кажется, производят идентичные результаты, вероятно, будучи просто совмещенными друг с другом) ,

textContentявляется частью Nodeинтерфейса, тогда как innerTextявляется частью HTMLElement. Это, например, означает, что вы можете «извлекать», textContentно не innerTextиз текстовых узлов:

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

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

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

Наконец, Safari 2.x также имеет ошибочную innerTextреализацию. В Safari innerTextфункционирует должным образом только в том случае, если элемент не является ни скрытым (через style.display == "none"), ни потерянным из документа. Иначе, innerTextприводит к пустой строке.

Я играл с textContentабстракцией (чтобы обойти эти недостатки), но она оказалась довольно сложной .

Лучше всего сначала определить свои точные требования и следовать оттуда. Часто можно просто лишить теги прочь innerHTMLэлемента, а не сделки со всеми возможными textContent/ innerTextотклонений.

Другая возможность, конечно, состоит в том, чтобы обходить дерево DOM и рекурсивно собирать текстовые узлы.


35
Chrome также поддерживает innerText, поэтому кажется, что Firefox - единственный крупный браузер, который НЕ поддерживает его. И IE - единственный браузер, который НЕ поддерживает textContent.
— Майк Нельсон

7
@mike - Но innerTextв Chrome он работает в 60 раз медленнее . jsperf.com/text-content/3
— gblazex

8
textContentтеперь поддерживается в IE9 +, но Firefox все еще не поддерживает innerText(хотя они добавили IE, представленный outerHTMLвсего несколько дней назад).
— Кангакс

1
Для тех, кому все еще нужно поддерживать IE8, здесь есть довольно полная Node.textContentразработка: github.com/usmonster/aight/blob/node-textcontent-shim/js/… (надеюсь, скоро будет включена в aight ).
— Нойо


83

Если вам нужно только установить текстовый контент, а не извлекать его, вот тривиальная версия DOM, которую вы можете использовать в любом браузере; для него не требуется расширение IE innerText или свойство 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));
}

Если в JavaScript нет оператора "! ==", я думаю, что оператор во второй строке должен быть просто "! =".
— RexE

23
@RexE: JavaScript имеет !==оператор, обратный к ===. Типочувствительное сравнение, используемое ===/ !==, обычно предпочтительнее, чем свободные компараторы ==/ !=.
— Бобинц

В Internet Explorer это не работает для установки текста тегов скрипта (я использовал их для шаблона). Вы установили `scriptTagElement.text = 'my template {{here}}';
— Кристофер Тарквини

Мне пришлось очень серьезно подумать, чтобы понять, почему вы использовали цикл (и я бы, !==nullкстати, отбросил его полностью) вместо того, чтобы просто заменить цикл на element.innerHTML=''(который должен выполнять ту же самую работу, что и цикл, а потом я вспомнил ... .: таблицы в (legacy-) IE ... ericvasilik.com/2006/07/code-karma.html Могу предложить добавить краткое описание «скрытого» и почти никогда не задокументированного «побочного эффекта» createTextNodeзамены amp lt и gt на их соответствующие сущности html-символов? Ссылка на точное поведение была бы грандиозной!
— GitaarLAB

26

jQuery предоставляет .text()метод, который можно использовать в любом браузере. Например:

$('#myElement').text("Foo");

22

Согласно ответу Prakash K, Firefox не поддерживает свойство innerText. Таким образом, вы можете просто проверить, поддерживает ли пользовательский агент это свойство, и действовать соответственно, как показано ниже:

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

2
'textContent' в элементе будет проще
— Джейми Пэйт,

if (elem.textContent! = null) тоже будет проще!
— Эльму

14

Действительно простая строка Javascript может получить текст «без тегов» во всех основных браузерах ...

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

2
Существует проблема с этим (по крайней мере, в IE8): если innerText является пустой строкой и textContent не определен, то (myElement.innerText || myElement.textContent) становится неопределенным.
— Магнус

1
Помимо ошибки, отмеченной @Magnus, также стоит учитывать тот факт, что существуют значительные различия в том, как textContentи innerTextсообщать о пробелах, которые могут иметь значение для некоторых случаев использования.
— Марк Амери

2
Просто добавьте еще один ||, то есть: var myText = (myElement.innerText || myElement.textContent || "") ;преодолеть неопределенное значение.
— PeterM

6

Обратите внимание, что Element::innerTextсвойство не будет содержать текст, который был скрыт стилем CSS " display:none" в Google Chrome (также оно будет отбрасывать контент, маскированный другой техникой CSS (включая размер шрифта: 0, цвет: прозрачный и несколько других подобных эффектов, которые делают текст не видимым).

Другие свойства CSS также учитываются:

  • Сначала анализируется стиль «display:» внутренних элементов, чтобы определить, разделяет ли он содержимое блока (например, «display: block», который является значением по умолчанию для элементов блока HTML во встроенной таблице стилей браузера, и поведение которого не было переопределено ваш собственный стиль CSS); в этом случае новая строка будет вставлена ​​в значение свойства innerText. Это не произойдет со свойством textContent.
  • Также будут учитываться свойства CSS, которые генерируют встроенное содержимое: например, встроенный элемент, <br \>который генерирует встроенную новую строку, также будет генерировать новую строку в значении innerText.
  • Стиль «display: inline» не вызывает новой строки ни в textContent, ни в innerText.
  • Стиль «display: table» генерирует новые строки вокруг таблицы и между строками таблицы, но «display: table-cell» генерирует символ табуляции.
  • Свойство position: absolute (используется с display: block или display: inline, это не имеет значения) также приведет к вставке разрыва строки.
  • Некоторые браузеры также включают разделение пробелов одним пробелом

Но Element::textContentвсе равно будет содержать ВСЕ содержимое внутренних текстовых элементов независимо от применяемого CSS, даже если они невидимы. И никакие дополнительные символы новой строки или пробелы не будут генерироваться в textContent, который просто игнорирует все стили и структуру, а также встроенные / блочные или позиционированные типы внутренних элементов.

Операция копирования / вставки с использованием выделения мышью отбрасывает скрытый текст в формате обычного текста, который помещается в буфер обмена, поэтому он не будет содержать все в textContent, а только то, что находится внутри innerText(после генерации пробелов / перехода на новую строку, как указано выше) ,

Оба свойства затем поддерживаются в Google Chrome, но их содержание может отличаться. Старые браузеры по-прежнему включали в innetText все, что сейчас содержит textContent (но их поведение в связи с последующим генерированием пробелов / новых строк было несовместимым).

jQuery разрешит эти несоответствия между браузерами, используя метод ".text ()", добавленный к проанализированным элементам, которые он возвращает с помощью запроса $ (). Внутренне это решает трудности, просматривая HTML DOM, работая только с уровнем «узла». Таким образом, он вернет что-то похожее на стандартный textContent.

Предостережение заключается в том, что этот метод jQuery не будет вставлять лишние пробелы или разрывы строк, которые могут быть видны на экране, вызванные подэлементами (например <br />) содержимого.

Если вы разрабатываете некоторые сценарии для обеспечения доступности, и ваша таблица стилей анализируется для неауристического рендеринга, например, плагинов, используемых для связи со средством чтения Брайля, этот инструмент должен использовать textContent, если он должен включать конкретные знаки пунктуации, которые добавляются в промежутки, стилизованные с помощью «display: none» и обычно включаются в страницы (например, для верхних индексов / подписок), в противном случае innerText будет очень запутанным для читателя Брайля.

Тексты, скрытые с помощью хитростей CSS, теперь обычно игнорируются основными поисковыми системами (которые также анализируют CSS ваших HTML-страниц, а также игнорируют тексты, не имеющие контрастных цветов на фоне), используя анализатор HTML / CSS и свойство DOM «innerText» точно так же, как в современных визуальных браузерах (по крайней мере, это невидимое содержимое не будет проиндексировано, поэтому скрытый текст не может быть использован в качестве трюка для принудительного включения некоторых ключевых слов на странице для проверки ее содержимого); но этот скрытый текст будет по-прежнему отображаться на странице результатов (если страница все еще была определена из индекса для включения в результаты), используя свойство textContent вместо полного HTML для удаления дополнительных стилей и сценариев.

Если вы назначите какой-либо простой текст в любом из этих двух свойств, это перезапишет внутреннюю разметку и примененные к ней стили (только назначенный элемент сохранит свой тип, атрибуты и стили), поэтому оба свойства будут содержать одинаковое содержимое. , Однако некоторые браузеры теперь больше не поддерживают запись в innerText и позволяют перезаписывать только свойство textContent (вы не можете вставлять разметку HTML при записи в эти свойства, поскольку специальные символы HTML будут правильно кодироваться с использованием числовых ссылок на символы, которые будут отображаться буквально. , если вы затем прочитаете innerHTMLсвойство после присвоения innerTextили textContent.


1
На самом деле «размер шрифта: 0», «цвет: прозрачный», «непрозрачность: 0», «отступ текста: -9999px» и т. Д. Включены в Chrome / WebKit innerText. В моих тестах игнорируются только «display: none» и «visibility: hidden».
— Кангакс

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

Редактировать (спасибо Mark Amery за комментарий ниже): Делайте это так, только если вы вне всякого сомнения знаете, что ни один код не будет полагаться на проверку существования этих свойств, как (например) jQuery . Но если вы используете jQuery, вы, вероятно, просто используете функцию «text» и делаете $ ('# myElement'). Text ('foo'), как показывают некоторые другие ответы.


4
-1; Это плохая идея. Код, в том числе код в библиотеках, таких как jQuery , очень часто проверяет наличие свойств innerTextили, textContentчтобы решить, какое из них использовать. Установив оба в строку, вы заставите чужой код, действующий на элементе, ошибочно обнаружить, что браузер поддерживает оба свойства; следовательно, этот код может плохо себя вести.
— Марк Амери

JQuery $ ('# myElement'). Val () работает для кросс-браузера.
— Тони Донг

4

innerTextбыл добавлен в Firefox и должен быть доступен в выпуске FF45: https://bugzilla.mozilla.org/show_bug.cgi?id=264412

Черновик спецификации был написан и, как ожидается, будет включен в стандарт HTML в будущем: http://rocallahan.github.io/innerText-spec/ , https://github.com/whatwg/html/issues/ 465

Обратите внимание, что в настоящее время реализации Firefox, Chrome и IE несовместимы. В дальнейшем мы можем ожидать, что Firefox, Chrome и Edge будут сходиться, в то время как старый IE остается несовместимым.

Смотрите также: https://github.com/whatwg/compat/issues/5


Есть ли в наличии полифилл?
— серв-ин

1
@user Это действительно зависит от того, что вам нужно. Если вам не нужно поддерживать старые версии Firefox и не беспокоиться о незначительных различиях в реализации, просто используйте innerText. Если textContentприемлемый запасной вариант и вам нужно поддерживать старый Fx, используйте (innerText || textContent). Если вам нужна одинаковая реализация во всех браузерах, я не верю, что для этого есть какой-то конкретный polyfill, но некоторые фреймворки (например, jQuery) могут уже реализовывать нечто подобное - обратитесь к другим ответам на этой странице.
— Боб

1
Функциональность innerText, а именно: видимый текст на странице, в Firefox> = 38 (для дополнения) По крайней мере, <script>теги должны быть полностью опущены. JQuery $('#body').text()не работал для меня. Но как обходной путь innerText || textContentв порядке. Спасибо.
— серв-ин

@uu Да, если вам нужна поддержка Fx 38, тогда этот ответ не применим. Вам придется жить с ограничениями / различиями textContentна данный момент.
— Боб

1

Как насчет этого?

//$elem is the jQuery object passed along.

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

** Мне нужно было сделать мой верхний регистр.


1
Дерьмовый раствор; это не работает, если элемент содержит что-то большее, чем один текстовый узел.
— Марк Амери

1

Как и в 2016 году от Firefox v45, innerTextработает на Firefox, посмотрите на его поддержку: http://caniuse.com/#search=innerText

Если вы хотите, чтобы он работал в предыдущих версиях Firefox, вы можете использовать его textContent, который лучше поддерживает Firefox, но хуже в старых версиях IE : http://caniuse.com/#search=textContent


0

Это был мой опыт innerText, textContent, innerHTMLи стоимость:

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

то есть = Internet Explorer, FF = Firefox, Ch = Google Chrome. примечание 1: ff работает до тех пор, пока значение не будет удалено с помощью backspace - см. примечание Ray Vega выше. примечание 2: работает немного в Chrome - после обновления оно не изменяется, затем вы щелкаете мышью и возвращаетесь в поле, и появляется значение. Лучший из лота elem.value = changeVal; который я не комментировал выше.


1
это только я ? или абосолютно игнорировать вопрос ОП? он попросил innerText / textContent, а вы в основном говорите о входных данных.
— Дементик

Этот ответ очень трудно прочитать. С другой стороны, я не уверен, что контент имеет достаточную ценность, чтобы его можно было привести в порядок.
— Марк Амери

-1

Просто репост из комментариев под оригинальным постом. innerHTML работает во всех браузерах. Спасибо Стефита.

myElement.innerHTML = "foo";


1
-1; innerHTMLне является адекватной заменой для textContent/, innerTextесли вы не уверены, что назначаемый вами текст не содержит никаких тегов или другого синтаксиса HTML. Для любых данных, предоставленных пользователем, у вас точно нет такой гарантии. Продвигать этот подход без этого предостережения опасно, учитывая, что это может привести к дырам в безопасности XSS . Имея так много безопасных подходов, нет причин даже рассматривать этот.
— Марк Эмери

Марк, я понимаю, что innerHTML - это нормальный способ записи данных в элементы html, такие как div, span, p. Я использую его для обработки возвращаемых данных JSON. Это тоже в JQuery ...
— Леонид Альжин

1
Если вы получите произвольную строку из ответа JSON и назначите ее элементу .innerHTML, ваш код будет поврежден и вы потенциально уязвимы для XSS. Что произойдет, если эта строка "<script>alert(1)</script>"?
— Марк Амери

1
@MarkAmery: HTML5 указывает, что <script>вставленный тег innerHTMLне должен выполняться. Но это не защищает старые браузеры. Кроме того, HTML5 innerHTMLНЕ защитит, например "<img src='x' onerror='alert(1)'>".
— GitaarLAB

-1

нашел это здесь:

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

Некоторое объяснение было бы хорошо! Кроме того, здесь есть какое-то странное дерьмо; зачем использовать условный комментарий, чтобы ограничить выполнение IE> = 8, а не только IE 8, если изначально IE> = 9 поддерживаетсяtextContent ? Стоит также отметить , что с тех пор innerTextи textContentимеют разные модели поведения, приведенный выше код не верный textContentрегулировочная шайба - это потенциально важным, но не обязательно очевидно!
— Марк Амери

спасибо за указание на недостаток, он был предназначен для IE <= 8
— simonarame

-2

Также возможно эмулировать innerTextповедение в других браузерах:

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

Просто глядя на проблемы с моей головы, сеттер не работает, preпотому что это удвоит переводы строки. Я подозреваю, что здесь больше не так.
— Марк Амери
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.