Каковы типичные причины, по которым Javascript, разработанный в Firefox, терпит неудачу в IE? [закрытый]

Я разработал некоторые расширенные страницы javascript, которые отлично работают на последних Firefox и Safari. Я пропустил проверку в Internet Explorer, и теперь я нахожу, что страницы не работают на IE 6 и 7 (до сих пор). Скрипты как-то не выполняются, страницы показывают, как будто javascript там не было, хотя некоторый javascript выполняется. Я использую собственные библиотеки с манипуляцией dom, из YUI 2 я использую Yui-Loader и XML-Http-запрос, а на одной странице Я использую "psupload", который зависит от На jQuery.

Я устанавливаю Microsoft Script Editor из Office XP и теперь буду отлаживать. Сейчас я также напишу конкретные тесты.

каковы типичные точки сбоя IE? В каком направлении я могу держать глаза открытыми.

Я нашел эту страницу, которая показывает некоторые различия. на странице: Quirksmode

можете ли вы по своему опыту назвать некоторые типичные вещи, которые я должен искать в первую очередь?

Я также задам больше вопросов здесь для конкретные задачи позже, но сейчас меня интересует ваш опыт, почему IE обычно терпит неудачу в сценариях, которые отлично работают в Firefox

Edit: Спасибо за все эти отличные ответы!

тем временем я адаптировал весь код, чтобы он также работал с Internet Explorer. Я интегрировал jQuery и построил свои собственные классы поверх него. Это была моя основная ошибка, что я не строил все свои вещи на jQuery с самого начала. Теперь Я иметь.

также JSLint мне очень помог.

и многие из отдельных вопросов из разных ответов помогли.

18 ответов


пожалуйста, не стесняйтесь, чтобы обновить этот список, если вы видите какие-либо ошибки/недочеты и т. д.

Примечание: IE9 исправляет многие из следующих проблем, поэтому многое из этого относится только к IE8 и ниже и в определенной степени IE9 в режиме причуд. Например, IE9 поддерживает SVG,<canvas>, <audio> и <video> изначально, однако вы должны включить режим соответствия стандартам для них, чтобы быть доступный.


общие:

  • проблемы с частично загруженными документами: это хорошая идея, чтобы добавить JavaScript в window.onload или аналогичное событие, поскольку IE не поддерживает многие операции в частично загруженных документах.

  • разными атрибутами: в CSS, это elm.style.styleFloat в IE vs elm.style.cssFloat в Firefox. В <label> теги это доступ с elm.htmlFor в IE vs elm.for в Firefox. Обратите внимание, что for зарезервировано в IE so elm['for'] вероятно, лучше остановить IE от создания исключения.


базовый язык JavaScript:

  • доступ к символам в строках: 'string'[0] не поддерживается в IE, поскольку это не в исходных спецификациях JavaScript. Использовать 'string'.charAt(0) или 'string'.split('')[0] отметить, что доступ к элементам в массивах значительно быстрее, чем с помощью charAt со строками в IE (хотя есть некоторые начальные расходы при split сначала называется.)

  • запятые перед окончанием объектов: например {'foo': 'bar',} не допускаются в IE.


специфические для элемента вопросы:

  • получение document из Элемент iframe:

    • Firefox и IE8+: IFrame.contentDocument (IE начал поддерживать это из версии 8.)
    • IE: IFrame.contentWindow.document
    • (IFrame.contentWindow относится к window в обоих браузерах.)

  • холст: версии IE до IE9 не поддерживают <canvas> элемент. IE поддерживает VML однако это аналогичная технология, и explorercanvas смогите обеспечить обертку на месте для <canvas> элементы для многих операций. Имейте в виду, что IE8 в режиме соответствия стандартам во много раз медленнее и имеет гораздо больше сбоев, чем в режиме причуд при использовании VML.

  • SVG: IE9 поддерживает SVG изначально. IE6-8 может поддерживать SVG, но только с внешние модули с поддержкой только некоторых из этих плагинов Манипуляции с JavaScript.

  • <audio> и <video>: поддерживаются только в IE9.

  • динамическое создание кнопки: IE document.createElement uncheckable. См. также как вы динамически создаете переключатель в Javascript, который работает во всех браузерах? для того, чтобы обойти этот.

  • встроенный JavaScript в <a href> теги и onbeforeunload конфликты в IE: если есть встроенный JavaScript в href часть a тег (например,<a href="javascript: doStuff()"> тогда IE всегда будет показывать сообщение, возвращенное из onbeforeunload если onbeforeunload обработчик удаляется заранее. См. также попросите подтвердить при закрытии вкладки.

  • <script> различия событий тегов: onsuccess и onerror не поддерживаются в IE и заменяются IE-специфичным onreadystatechange который запускается независимо от того, удалось ли загрузить или не удалось. См. также JavaScript Безумие для получения дополнительной информации.


размер элемента / положение / прокрутка и положение мыши:

  • получение размера/положения элемента: ширина/высота элементов иногда elm.style.pixelHeight/Width в IE, а не elm.offsetHeight/Width, но ни один из них не является надежным в IE, особенно в режиме причуд, и иногда один дает лучший результат, чем другой.

    elm.offsetTop и elm.offsetLeft часто неправильно сообщается, что приводит к неправильному поиску позиций элементов, поэтому всплывающие элементы и т. д. Во многих случаях отключены на несколько пикселей.

    также обратите внимание, что если элемент (или родитель элемента) имеет display of none тогда IE вызовет исключение при доступе атрибуты size / position вместо возврата 0 как Firefox делает.

  • получить размер экрана (получение видимой области экрана):

    • Firefox: window.innerWidth/innerHeight
    • IE стандартный режим: document.documentElement.clientWidth/clientHeight
    • режим совместимости в IE: document.body.clientWidth/clientHeight

  • положение прокрутки документа / положение мыши: этот на самом деле не определен w3c, поэтому он нестандартен даже в Firefox. Чтобы найти scrollLeft/scrollTop на document:

    • Firefox и IE в режиме совместимости: document.body.scrollLeft/scrollTop
    • IE в стандартном режиме: document.documentElement.scrollLeft/scrollTop
    • Примечание: некоторые другие браузеры использовать pageXOffset/pageYOffset как хорошо.

      function getDocScrollPos() {
       var x = document.body.scrollLeft ||
               document.documentElement.scrollLeft ||
               window.pageXOffset || 0,
           y = document.body.scrollTop ||
               document.documentElement.scrollTop ||
               window.pageYOffset || 0;
       return [x, y];
      };
      

    для того, чтобы получить позицию курсора мыши, evt.clientX и evt.clientY на mousemove события дадут положение относительно документа без добавления положения прокрутки таким образом, предыдущая функция должна быть incorporated:

    var mousepos = [0, 0];
    document.onmousemove = function(evt) {
     evt = evt || window.event;
     if (typeof evt.pageX != 'undefined') {
      // Firefox support
      mousepos = [evt.pageX, evt.pageY];
     } else {
      // IE support
      var scrollpos = getDocScrollPos();
      mousepos = [evt.clientX+scrollpos[0], evt.clientY+scrollpos[1]];
     };
    };
    

выбор/диапазон:

  • <textarea> и <input> выбор: selectionStart и selectionEnd не реализованы в IE, и на его месте есть собственная система "диапазонов", см. Также позиция курсора в textarea, в символах с самого начала.

  • получение выделенного текста в документ:

    • Firefox: window.getSelection().toString()
    • IE: document.selection.createRange().text


получение элементов по ID:

  • document.getElementById о name атрибут в формах (в зависимости от того, что определено первым в документе), поэтому лучше не иметь разных элементов, которые имеют одно и то же name и id. Это относится к тем дням, когда id не был стандартом w3c. document.all (собственническое IE-специфическое свойство) значительно быстрее, чем document.getElementById, но у него есть другие проблемы, поскольку он всегда приоритизирует name до id. Я лично использую этот код, отступая с дополнительными проверками, чтобы быть уверенным:

    function getById(id) {
     var e;
     if (document.all) {
      e = document.all[id];
      if (e && e.tagName && e.id === id) {
       return e;
      };
     };
     e = document.getElementById(id);
     if (e && e.id === id) {
      return e;
     } else if (!e) {
      return null;
     } else {
      throw 'Element found by "name" instead of "id": ' + id;
     };
    };
    

проблемы с только для чтения innerHTML:

  • IE делает не поддерживает установка innerHTML col, colGroup, frameSet, html, head, style, table, tBody, tFoot, tHead, title и tr элементы. Вот функция, которая работает вокруг этого для элементов, связанных с таблицей:

    function setHTML(elm, html) {
     // Try innerHTML first
     try {
      elm.innerHTML = html;
     } catch (exc) {
      function getElm(html) {
       // Create a new element and return the first child
       var e = document.createElement('div');
       e.innerHTML = html;
       return e.firstChild;
      };
      function replace(elms) {
       // Remove the old elements from 'elm'
       while (elm.children.length) {
        elm.removeChild(elm.firstChild);
       }
       // Add the new elements from 'elms' to 'elm'
       for (var x=0; x<elms.children.length; x++) {
        elm.appendChild(elms.children[x]);
       };
      };
      // IE 6-8 don't support setting innerHTML for
      // TABLE, TBODY, TFOOT, THEAD, and TR directly
      var tn = elm.tagName.toLowerCase();
      if (tn === 'table') {
       replace(getElm('<table>' + html + '</table>'));
      } else if (['tbody', 'tfoot', 'thead'].indexOf(tn) != -1) {
       replace(getElm('<table><tbody>' + html + '</tbody></table>').firstChild);
      } else if (tn === 'tr') {
       replace(getElm('<table><tbody><tr>' + html + '</tr></tbody></table>').firstChild.firstChild);
      } else {
       throw exc;
      };
     };
    };
    

    Также обратите внимание, что IE требует добавления <tbody> до <table> перед добавлением <tr>s в том, что <tbody> элемент при создании с помощью document.createElement, для пример:

    var table = document.createElement('table');
    var tbody = document.createElement('tbody');
    var tr = document.createElement('tr');
    var td = document.createElement('td');
    table.appendChild(tbody);
    tbody.appendChild(tr);
    tr.appendChild(td);
    // and so on
    

событие различия:

  • получение event переменной: события DOM не передаются функциям в IE и доступны как window.event. Один из распространенных способов получения события-использовать, например,
    elm.onmouseover = function(evt) {evt = evt||window.event}
    значение по умолчанию window.event если evt неопределено.

  • ключевые различия кода события: ключевое событие коды сильно различаются, хотя, если вы посмотрите на Quirksmode или JavaScript Безумие, это вряд ли специфично для IE, Safari и Opera снова отличаются.

  • событие Mouse различия: на button атрибут в IE-это бит-флаг, который позволяет сразу несколько кнопок мыши:

    • слева: 1 (var isLeft = evt.button & 1)
    • правильно: 2 (var isRight = evt.button & 2)
    • центр: 4 (var isCenter = evt.button & 4)

      модель W3C (поддерживается Firefox) менее гибка, чем модель IE, только с одной кнопкой, разрешенной сразу с левой стороны как 0, так как 2 и центр 1. Заметьте, что, как Петр-Павел Кох упоминает, это очень контр-интуитивный, как 0 обычно означает "нет кнопки".

      offsetX и offsetY are проблематично и, вероятно, лучше избегать их в IE. Более надежный способ получить offsetX и offsetY в IE было бы получить должность относительно расположенного элемента и вычесть его из clientX и clientY.

      Также обратите внимание, что в IE, чтобы получить двойной щелчок в click событие, которое вам нужно зарегистрировать как click и dblclick событие функции. Пожары в Firefox click а также dblclick при двойном щелчок, поэтому IE-специфическое обнаружение необходимо иметь такое же поведение.

  • различия в модели обработки событий: как проприетарная модель IE, так и модель Firefox поддерживают обработку событий снизу вверх, например, если есть события в обоих элементах <div><span></span></div> тогда события будут запускаться в span затем на div а не порядок, который они связаны, Если традиционный например,elm.onclick = function(evt) {} был использован.

    события"захвата" обычно поддерживаются только в Firefox и т. д., что вызовет div тут span события в порядке сверху вниз. Т. е. elm.setCapture() и elm.releaseCapture() для перенаправления событий мыши из документа в элемент (elm в этом случае) перед обработкой других событий, но они имеют ряд производительности и других проблем, поэтому, вероятно, следует избегать.

    • Firefox:

      прикрепить: elm.addEventListener(type, listener, useCapture [true/false])
      отключить: elm.removeEventListener(type, listener, useCapture)
      (type например 'mouseover' без on)

    • IE: только одно событие данного типа на элементе может быть добавлено в IE-исключение возникает, если добавлено более одного события того же типа. Также обратите внимание, что this относится к window вместо связанного элемента в функциях событий (так менее полезно):

      прикрепить: elm.attachEvent(sEvent, fpNotify)
      отключить: elm.detachEvent(sEvent, fpNotify)
      (sEvent например 'onmouseover')

  • различия атрибутов событий:

    • остановить события от обработки любым другим прослушиванием функции:

      Firefox: evt.stopPropagation()
      IE: evt.cancelBubble = true

    • остановить, например, ключевые события от вставки символов или остановки флажков от проверки:

      Firefox: evt.preventDefault()
      IE: evt.returnValue = false
      Примечание: только что вернулся false на keydown, keypress, mousedown, mouseup, click и reset также предотвратит дефолт.

    • получить элемент, который вызвал событие:

      Firefox: evt.target
      IE: evt.srcElement

    • получение элемента, от которого курсор мыши отошел: evt.fromElement в IE evt.target в Firefox, если в onmouseout событие, в противном случае evt.relatedTarget

    • получение элемента, на который переместился курсор мыши: evt.toElement в IE evt.relatedTarget в Firefox, если в onmouseout событие, в противном случае evt.target

    • Примечание: evt.currentTarget (элемент, к которому было привязано событие) не имеет эквивалента в IE.


проверьте также запятые, такие как эти или подобные, если они есть в вашем коде

var o={
'name1':'value1',
'name2':'value2',
} 

последняя запятая (после value2) будет допускаться Firefox, но не IE


Если вы придерживаетесь использования jQuery или YUI, поскольку ваш пост помечен, у вас должны быть минимальные различия между браузерами...вот для чего предназначены фреймворки, чтобы позаботиться об этих кросс-браузерных различиях для вас.

например, посмотрите на страница обхода quirksmode DOM, согласно ему IE не поддерживает большинство вещей...хотя true, фреймворки делают, например IE не поддерживает elem.childElementCount, но в jQuery: $(elem).children().size() работает, чтобы получить это значение, в каждом браузер. Вы обнаружите, что в библиотеке есть что-то для обработки 99% неподдерживаемых случаев в браузерах, по крайней мере, со скриптом...с CSS вам, возможно, придется перейти к плагинам для библиотеки, общим примером этого является получение закругленных углов, работающих в IE...поскольку у него нет поддержки CSS для таких.

Если, однако, вы начинаете делать вещи напрямую, например document.XXX(thing), тогда вы не в Библиотеке, вы делаете javascript напрямую (это все javascript, но вы получаете точку :), и это может или не может вызвать проблемы, в зависимости от того, насколько пьяна команда IE при реализации этой конкретной функции.

С IE вы с большей вероятностью потерпите неудачу при стилизации, выходящей правильно, чем необработанные проблемы javascript, анимации на несколько пикселей и тому подобное,много больше-так в IE6 конечно.


getElementbyID также будет соответствовать атрибуту name в IE, но не в других браузерах, и IE выберет то, что он найдет первым.

пример:

<script>
 var foo = document.getElementById('bar');
</script>

....
<input name="bar" type="text" />  //IE will get this element
<span id="bar"> Hello, World! </span>  //FF,Safari,Chrome will get this element

есть много вещей, но одна ловушка, в которую я попадал, заключалась в том, что многие браузеры принимают JSON без кавычек, в то время как ie6 и ie7 этого не делают.

{ name: "Jakob" } // will often work, but not in ie6/ie7
{ "name": "Jakob" } // Better!

редактировать: чтобы уточнить, это только проблема, когда требуется фактический JSON, в отличие от объектного литерала. JSON является подмножеством синтаксиса объектного литерала и подразумевается как формат обмена данными (например, XML), поэтому он предназначен для выбора.


Различная Поддержка JavaScript

IE не поддерживает (большинство) расширений, добавленных в JavaScript с 1.5.

новое в 1.6

  • Различными Методами - indexOf(), lastIndexOf(), every(), filter(), forEach(), map(), some()
  • for each ... in - выполняет итерацию значений вместо имен свойств.

новое в 1.7

новое в 1.8

  • Различными Методами - reduce(), reduceRight()
  • ярлыки для определения функций.

некоторые из этих вещей требуют, чтобы вы указали номер версии JavaScript для запуска под (который сломается в IE), но некоторые вещи, такие как [1,2,3].indexOf(2) может показаться, что это не так уж важно, пока вы не попытаетесь запустить его в IE


основные различия между JavaScript в IE и JavaScript в современных браузерах(например, Firefox) можно объяснить теми же причинами, что и различия в CSS/(X)HTML кросс-браузере. В то время не было стандарта де-факто; IE/Netscape/Opera воевали за территорию, реализуя большинство спецификаций, но также опуская некоторые, а также делая проприетарные спецификации, чтобы получить преимущества друг над другом. Я мог бы продолжить, но давайте перейдем к выпуску IE8: JavaScript был избегали / презирали в течение многих лет, и с ростом FF и презрением к webcomm, IE решил сосредоточиться в основном на продвижении своего CSS от IE6. И в основном оставил поддержку DOM позади. Поддержка DOM IE8 также может быть IE6, которая вышла в 2001 году....таким образом, поддержка DOM IE почти на десятилетие отстает от современных браузеров. Если у вас есть несоответствия JavaScript, особенно для движка макета, вам лучше всего атаковать его так же, как мы взяли на себя проблемы CSS; таргетинг на этот браузер. НЕ ИСПОЛЬЗОВАТЬ Браузер нюхает, использует обнаружение функций, чтобы вынюхать Ваш браузер / это уровень поддержки DOM.

JScript не является собственной реализацией ECMAScript IE; JScript был ответом IE на JavaScript Netscape, оба из которых появились до ECMAScript.

Что касается атрибутов типа в элементе скрипта, type="text/javascript" является стандартом по умолчанию (по крайней мере, в HTML5), поэтому вам никогда не понадобится атрибут типа, если ваш скрипт не является JavaScript.

As насколько IE не поддерживает innerHTML...innerHTML был изобретен IE и до сих пор не является стандартом DOM. Другие браузеры приняли его, потому что это полезно, поэтому вы можете использовать это кросс-браузер. Что касается динамически изменяющихся таблиц, MSDN говорит: "из-за конкретной структуры, требуемой таблицами,через свойство innerText и innerHTML свойства объектов table и tr доступны только для чтения."Я не знаю, насколько это было верно Изначально, но очевидно, что современный браузеры выяснили это, имея дело со сложностями компоновки таблиц.

Я настоятельно рекомендую прочитать PPK на JavaScript Джереми Кейт DOM Scripting JavaScript: Хорошие Части и Кристиана Хеллмана!--13-->начало JavaScript с помощью сценариев DOM и Ajax чтобы получить сильное представление о JavaScript.

Что касается фреймворков / библиотек, если у вас нет сильного хватайтесь за JavaScript еще, вы должны избегать их. 2 года назад я попал в ловушку jQuery, и хотя мне удалось совершить великолепные подвиги, я ни черта не узнал о кодировании JavaScript должным образом. Оглядываясь назад, jQuery-это злой удивительный инструментарий DOM, но моя неспособность узнать правильные замыкания, прототипическое наследование и т. д. я не только вернул свои личные знания, но и начал работать с огромными успехами, потому что понятия не имел, что делаю.

JavaScript-это язык браузера; Если вы клиентский / интерфейсный инженер, крайне важно, чтобы вы управляли JavaScript. Узел.js приносит JavaScript полный наклон, я вижу огромные шаги, предпринимаемые ежедневно в его развитии; серверный JavaScript будет стандартом в самом ближайшем будущем. Я упоминаю об этом, чтобы еще раз подчеркнуть, насколько важен JavaScript сейчас и будет.

JavaScript собирается сделать больше волн, чем рельсы.

Счастливый Сценариев!


некоторые собственные объекты доступны только для чтения, но не кажутся таковыми (вы можете писать им, но это не имеет никакого эффекта). Например, общий расширенный javascript основан на расширении Element объект путем переопределения системных методов, скажем, изменения элемента.прототип.appendChild () чтобы сделать больше, чем добавление дочернего узла - скажем, инициализировать его с данными родителя. Это приведет к сбою в IE6-исходный метод будет вызываться на новых объектах вместо нового.

в некоторых браузерах (Я не помню, что сейчас) считают новые строки между тегами HTML текстовыми узлами, а другие-нет. Поэтому childNodes (n), nextSibling (), firstChild () и тому подобное будут вести себя совершенно по-разному.


конечные запятые в массивах и объектных литералах были проблемой, недавно не проверялись (что означает IE8):

var a = [ 1, 2, 3, ];
var o = { a:1, b:2, c:3, };

это вызовет дополнительный код при создании таких структур на стороне сервера.


Я только что нашел один сегодня утром, коллега поставил тег script как: <script type="application/javascript"> потому что его автозаполнение ide было перед "text / javascript"

но, оказывается, IE просто игнорирует весь скрипт, если вы используете "application / javascript", вам нужно использовать"text/javascript"


Я нашел странную причуду только на днях с Internet Explorer. Я использовал YUI и заменил содержимое тела таблицы (), установив innerHTML

Y.one('#elementId').set('innerHTML', '<tr><td>Column 1</td></tr>');

это будет работать во всех браузерах, кроме IE. Я, наконец, обнаружил, что вы не можете заменить innerHTML таблицы в IE. Мне пришлось создать узел с помощью YUI, а затем добавить этот узел.

var myNode = Y.node.create('<tr><td>Column 1</td></tr>');
Y.one('#elementId').append(myNode);

Это было весело, чтобы разобраться!


дополнительные запятые и отсутствующие запятые были обычной проблемой в IE, пока она работает плавно на FF.


IE очень строго относится к отсутствию"; " так обычно и бывает.


для чего это стоит, я просто наткнулся на эту неприятную проблему в

скажем, у вас есть такой html:

<table><tr><td>some content...</td></tr></table>

и по какой-то причине (у меня был хороший) вам нужно получить весь HTML в таблице до последнего закрытия TR вы можете попробовать что-то вроде этого:

var tableHtml = document.getElementById('thetable').innerHTML;
var fragment = tableHtml.substring(0, tableHtml.lastIndexOf('</tr>'));


IE не является современным браузером и только следует ECMAScript свободно.


вы упомянули jQuery, с которым я менее знаком, но для общей справки, и в частности с прототипом, одна вещь, чтобы следить за зарезервированными словами / именами методов в IE. Я знаю, что меня часто достают такие вещи, как:

someElement.appendChild(new Element('label',{ **for**: someInput.id }).update( someLabelText );

(новый элемент (tagName, propertyHash) - это способ создания новых элементов в Protitype). В IE for: должно быть 'for':, потому что for - это зарезервированное слово. Что имеет полный смысл - но FireFox будет терпеть этот.

еще пример:

someElement.wrap('div').addClassName('someClass')

(том wrap метод в прототипе обертывает один элемент в другой) -- в IE, на textareas,wrap - это собственность, и Element.wrap() должны использоваться вместо methodized версия

эти два примера, которые приходят на ум из моего опыта. Они основаны на прототипе, но основная проблема не в этом: следите за любыми методами / метками/идентификаторами, которые IE считает зарезервированными словами, но FireFox или Safari будут терпеть.


дело в том, что IE не поддерживает JavaScript... Он поддерживает собственную реализацию ECMAScript: JScript... что немного отличается...


С помощью console.log() для вывода ошибок на консоль ошибок Firefox приведет к сбою ваших скриптов в IE. Нужно помнить, чтобы взять их, когда вы тестируете в IE.