'innerText' працює в IE, але не у Firefox


289

У мене є код JavaScript, який працює в IE, що містить таке:

myElement.innerText = "foo";

Однак, схоже, властивість 'innerText' не працює у Firefox. Чи є якийсь еквівалент Firefox? Або є більш загальна, перехресна властивість браузера, яку можна використовувати?


3
Це має зробити myElement.innerHTML = "foo";
stefita

Це замінить ВСЕ HTML в об'єкті на додане значення.
OMG Ponies

24
Тут бібліотеки на зразок jQuery полегшують життя, оскільки вони піклуються про невідповідності між веб-переглядачами, як це, дозволяючи використовувати стандартний фреймворк.
Dan Diplo

Але все-таки може підходити, якщо немає HTML, про який можна подбати.
Алекс Поло

21
Тож скажіть нам, як використовувати цю крос-браузерну альтернативу, а не просто говорити, що це можливо (що не конструктивно).
SasQ

Відповіді:


249

Firefox використовує властивість textContent, сумісну з W3C .

Я думаю, що Safari і Opera також підтримують цю власність.



2
@Bob Станом на 22 лютого 2016 року, все ще немає.
крильгар

@krillgar Це заплановано на Firefox 45, який повинен вийти на тиждень 8 березня. Він уже в поточному бета-релізі, і вже деякий час перебуває в полярному просторі. Це практично означає, що ви можете почати розробляти сайти innerTextлише за допомогою і очікуєте, що він буде працювати (з можливими химерностями) на всіх поточних браузерах найближчим часом, і старий IE теж.
Боб

1
FTR: innerTextце глибоко відрізняється від textContent, і на самому справі дуже корисно ( на здивуванні від передбачуваного IE примхи ...) innerTextнамагається дати наближення того , як текст на насправді представлений в браузері, абсолютно НЕ схожий textContent, що повертається тільки про tag- позбавлений джерела розмітки , додаючи мало значення або навіть додаткових проблем (наприклад, втрата меж слова).
Sz.

innerText досі не підтримує 2019 року у версії 64.
Тоні Донг

285

Оновлення : я написав допис у блозі, де детально описував усі відмінності .


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

Перш за все, textContentпредставлення пробілів відрізняється від innerTextодного. По-друге, і що ще важливіше, textContent включає весь вміст тегів SCRIPT , тоді як InternalText не робить.

Для того, щоб зробити щось цікавішим, 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/… (сподіваємось, незабаром буде включена у вісім ).
Нойо


83

Якщо вам потрібно лише встановити текстовий вміст, а не отримувати його, ось тривіальна версія DOM, яку ви можете використовувати в будь-якому браузері; воно не вимагає ні розширення IE innerText, ні властивості основного textContent рівня DOM рівня DOM.

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 є !==оператор, обернено ===. Типово-чутливе порівняння, яке використовується ===/ !==зазвичай є кращим порівняно з сипучими компараторами ==/ !=.
bobince

В Internet Explorer це не працює для встановлення тексту тегів сценарію (я використовував їх для шаблону). Ви встановили `scriptTagElement.text = 'мій шаблон {{тут}}';
Крістофер Таркіні

Мені довелося думати дуже важко, щоб зрозуміти, чому ви використовували цикл (і я !==nullдо речі відкинув би його повністю), а не просто замінювали цикл на element.innerHTML=''(що, як мабуть, зробити ту саму роботу, що і цикл, і тоді я згадав .. .: таблиці в (застарілому) IE ... ericvasilik.com/2006/07/code-karma.html Я можу запропонувати додати короткий опис "прихованого" та майже ніколи не задокументованого "побічного ефекту" createTextNodeзаміни підсилювача lt і gt до їх відповідних сутностей символів html? Посилання на його точну поведінку було б великим!
GitaarLAB


22

Відповідно до відповіді Пракаша К, Firefox не підтримує властивість innerText. Таким чином, ви можете просто перевірити, чи підтримує користувальницький агент це властивість, і продовжити відповідний спосіб, як показано нижче:

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

2
"textContent" в елемі буде простішим
Джеймі Пате

якщо (elem.textContent! = null) теж було б простіше!
Елмуе

14

Дійсно простий рядок Javascript може отримати текст "без тегів" у всіх основних браузерах ...

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

2
Існує проблема з цим (принаймні в IE8): Якщо InternalText порожній рядок, а textContent не визначено, то (myElement.innerText || myElement.textContent) стає невизначеним.
Магнус

1
Окрім помилки, яку зазначив @Magnus, також варто пам’ятати про те, що існують значні відмінності в тому, як textContentі innerTextповідомляти пробіл, який може мати значення для деяких випадків використання.
Марк Амері

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

6

Зауважте, що Element::innerTextвластивість не буде містити текст, який "" приховано стилем CSS у " display:noneGoogle Chrome", а також видалить вміст, замаскований іншими технологіями CSS (включаючи розмір шрифту: 0, колір: прозорий та кілька інших подібних ефектів, які призводять до того, що текст не відображатиметься видимим способом).

Також враховуються інші властивості CSS:

  • Спочатку стиль внутрішніх елементів "display:" аналізується, щоб визначити, чи він розмежовує вміст блоку (наприклад, "display: block", що є типовим для елементів блоку HTML у вбудованому стилі таблиці браузера, і поведінку якого не переосмислював власний стиль CSS); якщо так, у значення властивості innerText буде вставлено новий рядок. Це не відбудеться із властивістю textContent.
  • Властивості CSS, які генерують вбудований вміст, також будуть враховані: наприклад, елемент <br \>вбудованого рядка, який генерує вбудований новий рядок, також буде генерувати новий рядок у значенні innerText.
  • Стиль "display: inline" не викликає нового рядка ні в textContent, ні в InternalText.
  • Стиль "display: table" генерує нові рядки навколо таблиці та між рядками таблиці, але "display: table-cell" буде генерувати характер таблиць.
  • Властивість "позиція: абсолютний" (використовується з дисплеєм: блок або дисплей: вбудований, це не має значення) також призведе до вставки розриву рядка.
  • Деякі браузери також включатимуть єдиний пробіл між прольотами

Але Element::textContentвсе одно буде містити ВСІ вміст внутрішніх текстових елементів незалежно від застосованих CSS, навіть якщо вони невидимі. І ніяких зайвих нових рядків або пробілів не буде генеровано у textContent, який просто ігнорує всі стилі та структуру, вбудовані / блокові або розміщені типи внутрішніх елементів.

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

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

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

Застереження полягає в тому, що цей метод jQuery не буде вставляти зайвих пробілів або розривів рядків, які можуть бути видні на екрані, викликані підпунктами (як <br />) вмісту.

Якщо ви розробляєте деякі сценарії для доступності і ваш таблицю стилів розбирається для неслухового візуалізації, наприклад, плагіни, які використовуються для спілкування з читачем Брайля, цей інструмент повинен використовувати textContent, якщо він повинен містити конкретні знаки пунктуації, додані в проміжки, стилізовані з "display: none" і зазвичай містяться на сторінках (наприклад, для надписів / підписок), інакше InternalText буде дуже заплутаним для Braille Reader.

Тексти, приховані трюками 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";

Редагувати (дякую Марку Амерді за коментар нижче): Робіть це так, лише якщо ви знаєте поза розумним сумнівом, що жоден код не покладається на перевірку існування цих властивостей, як (наприклад, jQuery ) . Але якщо ви використовуєте jQuery, ви, ймовірно, просто використовуєте функцію "текст" і виконайте $ ('# 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/isissue/ 465

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

Дивіться також: https://github.com/whatwg/compat/isissue/5


Чи є поліфіл в наявності?
серв-інк

1
@user Це дійсно залежить від того, що вам потрібно. Якщо вам не потрібно підтримувати старіші версії Firefox і не переймаєтесь незначними відмінностями у впровадженні, просто використовуйте innerText. Якщо textContentце прийнятна резервна копія і вам потрібно підтримувати старий Fx, тоді використовуйте (innerText || textContent). Якщо ви хочете ідентичну реалізацію для всіх браузерів, я не вірю, що для цього є якась поліфіл, але деякі рамки (наприклад, jQuery) вже можуть реалізувати щось подібне - див. Інші відповіді на цій сторінці.
Боб

1
Функціональність innerText, тобто: видимий текст на сторінці, у Firefox> = 38 (для додатка) Принаймні, <script>теги повинні бути повністю опущені. jQuery $('#body').text()не працював для мене. Але як вирішити innerText || textContentвсе нормально. Дякую.
серв-ін

@user Так, якщо вам потрібно підтримати 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 працює, поки після видалення значення із зворотної області - див. примітку Рея Вега вище. Примітка 2: працює дещо в хромі - після оновлення воно не змінюється, потім ви клацаєте геть і натискаєте назад у поле і з'являється значення. Найкраще з партії elem.value = changeVal; що я не коментував вище.


1
це тільки я? чи абоболу ігнорувати питання про ОП? він попросив InternalText / 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");
         }
     });
 }

Тільки шукаючи проблеми у верхній частині моєї голови, сетер зламається за pres, оскільки він подвоїть нові рядки. Я підозрюю, що тут є більше неправильного.
Марк Амері
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.