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


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

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

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

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

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

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

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

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

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

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

18 107

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 так elm['for'] - это, наверное, лучшая идея, чтобы остановить т. е. от повышения исключение.


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

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

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


вопросы, связанные с элементами:

  • получение document из IFrame:

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

  • холст: версии IE до IE9 не поддерживают <canvas> элемент. Т. е. поддерживает ли 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-specific onreadystatechange который запускается независимо от того, удалось ли загрузить или не удалось. Смотрите также JavaScript Madness для получения дополнительной информации.


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

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

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

    также обратите внимание, что если элемент (или родитель элемента) имеет display на none затем т. е. будет вызывать исключение при доступе к размер/положение атрибутами вместо того, чтобы возвратить 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 события дадут положение относительно документа без добавления позиции прокрутки таким образом, предыдущая функция должна быть включены:

    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]];
     };
    };
    

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


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

  • document.getElementById о name атрибут в формах (в зависимости от того, что определено первым в документе), поэтому лучше не иметь разных элементов, которые имеют одно и то же name и id. Это восходит к тем временам, когда id не был стандартом w3c. document.all (проприетарный т. е.-конкретный объект недвижимости) значительно быстрее, чем 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:

  • т. е. не не поддерживает установка 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 Madness, это вряд ли относится к IE, Safari и Opera снова отличаются.

  • событие Mouse различия: the 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 являются проблематично и, вероятно, лучше избегать их в IE. Более надежный способ получить offsetX и offsetY в IE было бы получить должность относительно расположенного элемента и вычесть его из clientX и clientY.

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

  • различия в модели обработки событий: как собственная модель IE, так и модель Firefox поддерживают обработку событий снизу вверх, например, если есть события в обоих элементах <div><span></span></div> тогда события будут запускаться в spanзатем the 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 in 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 не поддерживает большинство вещей...хотя это правда, фреймворки делают, например 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!

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

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

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

новое в 1.6

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

New 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....so поддержка DOM от IE почти на десять лет отстает от современных браузеров. Если у вас есть несоответствия JavaScript, характерные для движка макета, вам лучше всего атаковать его так же, как мы взяли на себя проблемы CSS; таргетинг на этот браузер. НЕ ИСПОЛЬЗОВАТЬ Браузер нюхает, используйте обнаружение функций, чтобы вынюхать Ваш браузер/это уровень поддержки DOM.

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

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

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

Я настоятельно рекомендую прочитать PPK на JavaScript Джереми Кейт DOM Scripting JavaScript: Хорошие Части и Кристиана Хеллмана начиная 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')

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

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

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

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