在 Firefox 上开发的 Javascript 在 IE 上失败的典型原因是什么?

IT技术 jquery firefox yui javascript
2021-03-07 15:43:20

我开发了一些 javascript 增强页面,它们在最近的 Firefox 和 Safari 上运行良好。我错过了检查 Internet Explorer,现在我发现这些页面在 IE 6 和 7(到目前为止)上不起作用。脚本以某种方式未执行,页面显示好像 javascript 不存在,尽管执行了一些 javascript。我使用自己的 dom 操作库,从 YUI 2 我使用 YUI-Loader 和 XML-Http-Request,在一个页面上我使用“psupload”,这取决于 JQuery。

我正在从 Office XP 安装 Microsoft 脚本编辑器,现在将进行调试。我现在也会写具体的测试。

IE 的典型失败点是什么?我可以睁开眼睛的方向是什么。

我找到了这个页面,其中显示了一些差异。访问:Quirksmode

你能根据你的经验说出一些我应该首先寻找的典型事物吗?

稍后我还将在这里针对特定任务提出更多问题,但现在我对您的经验感兴趣,为什么 IE 通常在 Firefox 中运行良好的脚本上失败

编辑:谢谢你所有这些伟大的答案!

与此同时,我已经修改了整个代码,以便它也适用于 Internet Explorer。我现在集成了 jQuery 并在它之上构建了我自己的类。这是我的基本错误,我没有从一开始就在 jQuery 上构建我所有的东西。我现在有。

JSLint 也帮了我很多。

来自不同答案的许多单一问题都有帮助。

6个回答

如果您发现任何错误/遗漏等,请随时更新此列表。

注意: IE9 修复了以下许多问题,因此其中很多仅适用于 IE8 及以下版本,并且在一定程度上适用于 quirks 模式下的 IE9。例如,IE9支持SVG, <canvas><audio><video>原生,但是你必须让符合标准的模式为他们提供。


##一般的:

  • 部分加载文档的问题:window.onloadIE 或类似事件中添加 JavaScript 是个好主意,因为 IE 不支持部分加载文档中的许多操作。

  • 不同的属性:在 CSS 中,它elm.style.styleFloat在 IE 和elm.style.cssFloatFirefox 中。<label>标签中forelm.htmlFor在 IE 和elm.forFirefox 中访问属性请注意,这for是在 IE 中保留的,因此elm['for']阻止 IE 引发异常可能是一个更好的主意。


##Base JavaScript 语言:

  • 访问字符串中的字符'string'[0]在 IE 中不受支持,因为它不在原始 JavaScript 规范中。使用'string'.charAt(0)'string'.split('')[0]注意访问数组中的项目比charAt在 IE 中使用字符串要快得多(尽管split第一次调用时会有一些初始开销。)

  • 对象结尾前的逗号:例如{'foo': 'bar',},在 IE 中是不允许的。


##Element 特定问题:

  • 获取documentIFrame 的

    • Firefox 和 IE8+:( IFrame.contentDocument IE从版本 8开始支持此功能。)
    • IE: IFrame.contentWindow.document
    • 在两种浏览器中都IFrame.contentWindow指代window。)

  • Canvas: IE9 之前的 IE 版本不支持该<canvas>元素。IE 确实支持VML,这是一种类似的技术,但是explorercanvas可以<canvas>为许多操作的元素提供就地包装请注意,标准合规模式下的 IE8 比使用 VML 时在 quirks 模式下要慢很多倍,并且有更多的故障。

  • SVG: IE9 原生支持 SVG。IE6-8 可以支持 SVG,但只能使用外部插件,其中只有一些插件支持 JavaScript 操作。

  • <audio><video>:仅在 IE9 中受支持。

  • 动态创建单选按钮: IE <8 有一个错误,使创建的单选按钮document.createElement不可检查。另请参阅如何在 Javascript 中动态创建适用于所有浏览器的单选按钮?解决这个问题的方法。

  • <a href>标签中嵌入的 JavaScriptonbeforeunloadIE 中的冲突:如果标签href一部分中嵌入了 JavaScript a(例如,<a href="javascript: doStuff()">IE 将始终显示返回的消息,onbeforeunload除非onbeforeunload事先删除处理程序。另请参阅关闭选项卡时要求确认

  • <script>标记事件差异: onsuccess并且onerror在 IE 中不受支持,并由特定于 IE 的 IE 替换onreadystatechange,无论下载成功还是失败都会触发。有关更多信息,另请参阅JavaScript Madness


##元素大小/位置/滚动和鼠标位置:

  • 获取元素大小/位置:元素的宽度/高度有时elm.style.pixelHeight/Width在 IE 中而不是在 IE 中elm.offsetHeight/Width,但两者在 IE 中都不可靠,尤其是在 quirks 模式下,有时一个比另一个给出更好的结果。

elm.offsetTop并且elm.offsetLeft经常被错误地报告,导致查找元素的位置不正确,这就是为什么弹出元素等在很多情况下会偏离几个像素的原因。

另请注意,如果元素(或元素的父元素)具有displayof,none则 IE 将在访问大小/位置属性时引发异常,而不是0像 Firefox 那样返回

  • 获取屏幕尺寸(获取屏幕的可视区域):

    • 火狐: window.innerWidth/innerHeight
    • IE标准模式: document.documentElement.clientWidth/clientHeight
    • IE 怪癖模式: document.body.clientWidth/clientHeight

  • 文档滚动位置/鼠标位置:这实际上不是由 w3c 定义的,因此即使在 Firefox 中也是非标准的。查找scrollLeft/scrollTopdocument

    • Firefox 和 IE 的 quirks 模式: 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.clientXevt.clientYmousemove事件会给相对于文档的位置不添加滚动位置,因此先前的功能将需要纳入:

     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专有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 colcolGroupframeSethtmlheadstyletabletBodytFoottHeadtitle,和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在创建 using 时需要在将s附加到该元素之前将<tbody>a添加到 a ,例如:<table><tr><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. 获取事件的一种常用方法是使用 eg
    elm.onmouseover = function(evt) {evt = evt||window.event}
    ,默认为window.eventif evtis undefined。

  • 关键事件代码差异:关键事件代码千差万别,但如果您查看QuirksmodeJavaScript Madness,它几乎不是特定于 IE 的,Safari 和 Opera 再次不同。

  • 鼠标事件区别: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请注意,正如 Peter-Paul Koch 所提到的,这是非常违反直觉的,0通常意味着“没有按钮”。

    offsetX并且offsetY有问题的,最好在 IE 中避免它们。更可靠的方式来获得的offsetX,并offsetY在IE浏览器将获得位置相对定位的元素和减去它clientXclientY

    另请注意,在 IE 中要在click事件中双击,您需要将 aclickdblclickevent都注册到函数。Firefox的火灾click以及dblclick双时点击,因此需要IE专用检测到具有相同的行为。

  • 在事件处理的不同模式:无论是专有的IE模型和事件从下往上火狐模型的支持处理,例如,如果有在这两个元素的事件<div><span></span></div>,然后将事件的触发span ,然后div,而不是它们是秩序如果使用传统的 eg,elm.onclick = function(evt) {}绑定

    “捕获”事件通常仅在 Firefox 等中受支持,这将按自上而下的顺序触发divthenspan事件。IE 有elm.setCapture()elm.releaseCapture()用于elm在处理其他事件之前将鼠标事件从文档重定向到元素(在这种情况下),但它们有许多性能和其他问题,因此可能应该避免。

    • 火狐:

      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'

  • 事件属性差异:

    • 停止事件被任何其他监听函数处理

      火狐 evt.stopPropagation()
      浏览器: evt.cancelBubble = true

    • 停止例如关键事件插入字符或停止检查复选框:

      火狐浏览器: evt.preventDefault()
      IE: evt.returnValue = false
      注:刚回来falsekeydownkeypressmousedownmouseupclickreset也将避免违约。

    • 获取触发事件的元素:

      火狐 evt.target
      浏览器: evt.srcElement

    • 获取鼠标光标移开的元素: evt.fromElement在 IE 中evt.target,如果在onmouseout事件中,在 Firefox 中,否则evt.relatedTarget

    • 获取鼠标光标移动到的元素: evt.toElement在 IE 中evt.relatedTarget,如果在onmouseout事件中,在 Firefox 中,否则evt.target

    • 注意:( evt.currentTarget事件绑定到的元素)在 IE 中没有等价物。

非常,非常,非常好的清单!感谢所有贡献的人:)
2021-05-15 15:43:20

如果您的代码中有逗号,请检查这些或类似的逗号

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

最后一个逗号(在 value2 之后)将被 Firefox 接受,但不能被 IE 接受

哦,补充一下@SeanJA 的评论:我最近切换到 NetBeans,它确实抓住了这一点。
2021-04-30 15:43:20
+1,我经常遇到这个。
2021-05-05 15:43:20
我第一次做一些 JS 工作时,我在这上面浪费了很多时间。现在是我检查的第一件事!诅咒蹩脚的 Textmate 扩展,留下逗号。
2021-05-09 15:43:20
如果可以的话,我会给你+10 - 这一直发生在我身上。
2021-05-14 15:43:20
大多数优秀的编辑都应该抓住这个
2021-05-15 15:43:20

如果你坚持使用 jQuery 或 YUI 作为你的帖子被标记,你应该有浏览器之间的最小差异......这就是框架的用途,为你处理这些跨浏览器的差异。

举个例子,看看quirksmode DOM traversal page,根据它 IE 不支持大多数东西......虽然是真的,框架支持elem.childElementCount例如 IE 不支持,但在 jQuery 中:$(elem).children().size()可以获取这个值,在每个浏览器中。您会发现库中有一些东西可以处理跨浏览器 99% 的不受支持的情况,至少使用脚本...在 IE 中工作...因为它没有 CSS 支持。

但是,如果您开始直接做事,例如document.XXX(thing),那么您不在库中,而是直接在做 javascript(这都是 javascript,但您明白了:),这可能会或可能不会导致问题,具体取决于如何IE 团队在实现该特定功能时喝醉了。

与IE浏览器你就更有可能失败的造型现身权不是原始的JavaScript问题,动画几个像素关闭,诸如此类的事情,在IE6更所以当然。

如果你使用像 Netbeans 这样的 IDE,你可以为你的 javascript 设置目标浏览器,当你做一些似乎不受支持的事情时,它也会通过警告你来帮助你。
2021-05-05 15:43:20
我现在明白多了。是的,我也直接做了这样的事情。卡尔索瓦尔德
2021-05-08 15:43:20

getElementbyID 也将匹配 IE 中的 name 属性,但不会匹配其他浏览器,并且 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
抱歉粗鲁,但 IE 真的很丑
2021-05-03 15:43:20
document.getElementByIdOrNameIGuessWhateverMan(id);
2021-05-17 15:43:20

有很多事情,但我曾经陷入的一个陷阱是,许多浏览器接受不带引号的 JSON,而 ie6 和 ie7 不接受。

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

编辑:澄清一下,这只是需要实际 JSON 时的问题,而不是对象文字。JSON 是对象字面量语法的一个子集,旨在作为一种数据交换格式(如 XML),这就是它被设计为更挑剔的原因。

请注意,这取决于上下文,对象文字很好,JSON 不是……但例如 jQuery 在其最新版本中根本不允许无效 JSON。
2021-04-30 15:43:20
不是我的反对……但你应该向其他人澄清这一点,然后从我那里+1。
2021-05-01 15:43:20