«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 и рекурсивно собирать текстовые узлы.

kangax
источник
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));
}
bobince
источник
Если в 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");
user161433
источник
22

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

function changeText(elem, changeVal) {
    if (typeof elem.textContent !== "undefined") {
        elem.textContent = changeVal;
    } else {
        elem.innerText = changeVal;
    }
}
RISM
источник
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.

verdy_p
источник
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'), как показывают некоторые другие ответы.

Kwateco
источник
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();

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

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

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

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

Vandervals
источник
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]-->
simonarame
источник
Некоторое объяснение было бы хорошо! Кроме того, здесь есть какое-то странное дерьмо; зачем использовать условный комментарий, чтобы ограничить выполнение 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");
         }
     });
 }
DitherSky
источник
Просто глядя на проблемы с моей головы, сеттер не работает, preпотому что это удвоит переводы строки. Я подозреваю, что здесь больше не так.
Марк Амери