在 Firefox 上开发的 Javascript 在 IE 上失败的典型原因是什么? [英] What are the typical reasons Javascript developed on Firefox fails on IE?
问题描述
我开发了一些 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 也帮了我很多.
来自不同答案的许多单一问题都有帮助.
如果您发现任何错误/遗漏等,请随时更新此列表.
注意: IE9 修复了以下许多问题,因此其中大部分仅适用于 IE8 及以下版本,并且在一定程度上适用于 quirks 模式下的 IE9.例如,IE9 原生支持 SVG、、
和
,但是你必须 启用标准合规模式 以便它们可用.
##General:
部分加载文档的问题:最好将 JavaScript 添加到
window.onload
或类似事件中,因为 IE 不支持许多操作在部分加载的文档中.不同的属性:在 CSS 中,IE 中的
elm.style.styleFloat
与 Firefox 中的elm.style.cssFloat
.在标签中,
for
属性在 IE 中使用elm.htmlFor
访问,而elm.for
在火狐.请注意,for
在 IE 中是保留的,因此elm['for']
可能是阻止 IE 引发异常的更好主意.
##Base JavaScript 语言:
访问字符串中的字符:IE 不支持
'string'[0]
,因为它不在原始 JavaScript 规范中.使用'string'.charAt(0)
或'string'.split('')[0]
注意到访问数组中的项目比使用快得多charAt
在 IE 中带有字符串(尽管第一次调用split
时会有一些初始开销.)对象结尾前的逗号:例如
{'foo': 'bar',}
在 IE 中是不允许的.
##Element 特定问题:
获取 IFrame 的
document
:- Firefox 和 IE8+:
IFrame.contentDocument
(IE 开始支持此 来自版本 8.) - IE:
IFrame.contentWindow.document
- (
IFrame.contentWindow
指的是两个浏览器中的window
.)
- Firefox 和 IE8+:
Canvas:IE9 之前的 IE 版本不支持
元素.IE 确实支持 VML 但是这是一种类似的技术,并且 explorercanvas 可以为许多操作的
元素提供就地包装.请注意,在使用 VML 时,标准合规模式下的 IE8 比 quirks 模式下的 IE8 慢很多倍,故障也多得多.
SVG: IE9 原生支持 SVG.IE6-8 可以支持 SVG,但只有 外部插件,其中只有一些插件支持 JavaScript 操作.
和
: 仅在 IE9 中受支持.
动态创建单选按钮: IE <8 有一个错误,使使用
document.createElement
创建的单选按钮无法检查.另见 您如何在 Javascript 中动态创建适用于所有浏览器的单选按钮? 寻找解决此问题的方法.标签中嵌入的 JavaScript 和 IE 中的
onbeforeunload
冲突: 如果中嵌入了 JavaScript>href
a
标记的一部分(例如然后 IE 将始终显示消息从
onbeforeunload
返回,除非onbeforeunload
处理程序被事先删除.另见 关闭标签页时要求确认.标签事件差异:
onsuccess
和onerror
不支持IE 并由特定于 IE 的onreadystatechange
替换,无论下载是成功还是失败都会触发该onreadystatechange
.另请参阅 JavaScript 疯狂了解更多信息.
##Element 大小/位置/滚动和鼠标位置:
- 获取元素大小/位置:元素的宽度/高度在 IE 中有时是
elm.style.pixelHeight/Width
而不是elm.offsetHeight/Width
,但两者在 IE 中都不可靠,尤其是在 quirks 模式下,有时一个比另一个给出更好的结果.
elm.offsetTop
和 elm.offsetLeft
经常报错,导致查找元素位置不正确,这就是为什么弹出元素等在很多案例.
另请注意,如果元素(或元素的父元素)的 display
为 none
,则 IE 将在访问大小/位置属性时引发异常,而不是像 Firefox 一样返回 0
.
获取屏幕尺寸(获取屏幕的可视区域):
- Firefox:
window.innerWidth/innerHeight
- IE 标准模式:
document.documentElement.clientWidth/clientHeight
- IE 怪癖模式:
document.body.clientWidth/clientHeight
- Firefox:
文档滚动位置/鼠标位置:这个实际上没有被 w3c 定义,所以即使在 Firefox 中也是非标准的.找到
document
的scrollLeft
/scrollTop
:Firefox 和 IE 的 quirks 模式:
document.body.scrollLeft/scrollTop
IE 标准模式:
document.documentElement.scrollLeft/scrollTop
注意:其他一些浏览器也使用
pageXOffset
/pageYOffset
.函数 getDocScrollPos() {var x = document.body.scrollLeft ||document.documentElement.scrollLeft ||window.pageXOffset ||0,y = document.body.scrollTop ||document.documentElement.scrollTop ||window.pageYOffset ||0;返回 [x, y];};
为了获取鼠标光标的位置,
mousemove
事件中的evt.clientX
和evt.clientY
会给出相对的位置到文档不添加滚动位置,因此需要合并以前的功能:var mousepos = [0, 0];document.onmousemove = 函数(evt){evt = evt ||窗口事件;如果(typeof evt.pageX != '未定义'){//火狐支持mousepos = [evt.pageX, evt.pageY];} 别的 {//IE支持var scrollpos = getDocScrollPos();mousepos = [evt.clientX+scrollpos[0], evt.clientY+scrollpos[1]];};};
##选择/范围:
和
选择:
selectionStart
和selectionEnd
没有在 IE 中实现,并且有一个专有的范围"系统,另见 如何获取插入符号列(不是像素)位置在文本区域中,以字符形式,从一开始?.获取文档中当前选定的文本:
- Firefox:
window.getSelection().toString()
- IE:
document.selection.createRange().text
- Firefox:
##通过 ID 获取元素:
document.getElementById
也可以引用表单中的name
属性(取决于哪个在文档中首先定义)所以最好不要有不同的元素具有相同的name
和id
.这可以追溯到id
不是 w3c 标准的时代.document.all
(专有的 IE 特定属性)明显快于document.getElementById
,但它还有其他问题,因为它总是将name
放在id
之前.我个人使用此代码,并通过附加检查回退以确保:函数 getById(id) {变量 e;如果(文件.所有){e = document.all[id];if (e && e.tagName && e.id === id) {返回 e;};};e = document.getElementById(id);if (e && e.id === id) {返回 e;} else if (!e) {返回空;} 别的 {throw '按名称"找到的元素而不是id":' + id;};};
##只读innerHTML 的问题:
IE 不不支持设置
col
、colGroup
、frameSet
、html
、head
、style
、table
、tBody
、tFoot
、tHead
、title
和tr
元素.这是一个用于解决与表格相关的元素的函数:function setHTML(elm, html) {//首先尝试innerHTML尝试 {elm.innerHTML = html;}赶上(排除){函数 getElm(html) {//创建一个新元素并返回第一个子元素var e = document.createElement('div');e.innerHTML = html;返回 e.firstChild;};功能替换(榆树){//从 'elm' 中删除旧元素而 (elm.children.length) {elm.removeChild(elm.firstChild);}//将 'elms' 中的新元素添加到 'elm'for (var x=0; x
' + html + ''));} 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);} 别的 {抛出 exc;};};}; 另请注意,IE 要求在将
附加到 之前,将 添加到
使用
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);//等等
##事件差异:
获取
event
变量: DOM 事件不会传递给 IE 中的函数,并且可以作为window.event
访问.获取事件的一种常见方法是使用例如elm.onmouseover = function(evt) {evt = evt||window.event}
默认为window.event
如果evt
未定义.关键事件代码差异:关键事件代码差异很大,但如果您查看 Quirksmode 或 JavaScript Madness,它几乎不是特定于IE、Safari 和 Opera 又不同了.
鼠标事件差异: IE 中的
button
属性是一个位标志,允许同时使用多个鼠标按钮:- 左: 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 中避免它们.在 IE 中获取offsetX
和offsetY
的更可靠方法是 获取相对定位元素的位置,并将其从clientX
和clientY
中减去.另请注意,在 IE 中要在
click
事件中获得双击,您需要同时注册click
和dblclick
事件到一个函数.Firefox 会在双击时触发click
以及dblclick
,因此需要特定于 IE 的检测才能具有相同的行为.- 左: 1 (
事件处理模型的差异:专有 IE 模型和 Firefox 模型都支持自下而上的事件处理,例如如果
的两个元素中都有事件,则事件将在
span
中触发然后div
而不是它们绑定的顺序,如果是传统的 eg使用了elm.onclick = function(evt) {}
.捕获"事件通常仅在 Firefox 等中支持,这将按自上而下的顺序触发
div
然后是span
事件.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'
)
事件属性差异:
阻止事件被任何其他监听函数处理:
Firefox:
evt.stopPropagation()
IE:evt.cancelBubble = true
停止例如插入字符或阻止复选框被选中的关键事件:
Firefox:
evt.preventDefault()
IE:evt.returnValue = false
注意: 只需在keydown
、keypress
、mousedown
、中返回
、false
mouseupclick
和reset
也将阻止默认.获取触发事件的元素:
火狐:
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 中没有等效项.
I developed some javascript enhanced pages that run fine on recent Firefox and Safari. I missed to check in Internet Explorer, and now I find the pages don't work on IE 6 and 7 (so far). The scripts are somehow not executed, the pages show as if javascript wasn't there, although some javascript is executed. I am using own libraries with dom manipulation, from YUI 2 I use YUI-Loader and the XML-Http-Request, and on one page I use "psupload", which depends on JQuery.
I am installing Microsoft Script Editor from Office XP and will now debug. I will also write specific tests now.
What are the typical failing points of IE? What direction I can keep my eyes open.
I found this page, which shows some differences. visit: Quirksmode
Can you from your experience name some typical things I should look for first?
I will also ask more questions here for specific tasks later, but for now I am interested in your experience why IE usually fails on scripts that run fine in Firefox
Edit: Thank you for all those great answers!
In the meantime I have adapted the whole code so that it also works with Internet Explorer. I integrated jQuery and built my own classes on top of it now. This was my basic mistake, that I did not build all my stuff on jQuery from the beginning. Now I have.
Also JSLint helped me a lot.
And many of the single issues from the different answers helped.
解决方案Please feel free to update this list if you see any errors/omissions etc.
Note: IE9 fixes many of the following issues, so a lot of this only applies to IE8 and below and to a certain extent IE9 in quirks mode. For example, IE9 supports SVG,
<canvas>
,<audio>
and<video>
natively, however you must enable standards compliance mode for them to be available.
##General:
Problems with partially loaded documents: It’s a good idea to add your JavaScript in a
window.onload
or similar event as IE doesn’t support many operations in partially loaded documents.Differing attributes: In CSS, it's
elm.style.styleFloat
in IE vselm.style.cssFloat
in Firefox. In<label>
tags thefor
attribute is accessed withelm.htmlFor
in IE vselm.for
in Firefox. Note thatfor
is reserved in IE soelm['for']
is probably a better idea to stop IE from raising an exception.
##Base JavaScript language:
Access characters in strings:
'string'[0]
isn’t supported in IE as it’s not in the original JavaScript specifications. Use'string'.charAt(0)
or'string'.split('')[0]
noting that accessing items in arrays is significantly faster than usingcharAt
with strings in IE (though there's some initial overhead whensplit
is first called.)Commas before the end of objects: e.g.
{'foo': 'bar',}
aren't allowed in IE.
##Element-specific issues:
Getting the
document
of an IFrame:- Firefox and IE8+:
IFrame.contentDocument
(IE started supporting this from version 8.) - IE:
IFrame.contentWindow.document
- (
IFrame.contentWindow
refers to thewindow
in both browsers.)
- Firefox and IE8+:
Canvas: Versions of IE before IE9 don't support the
<canvas>
element. IE does support VML which is a similar technology however, and explorercanvas can provide an in-place wrapper for<canvas>
elements for many operations. Be aware that IE8 in standards compliance mode is many times slower and has many more glitches than when in quirks mode when using VML.SVG: IE9 supports SVG natively. IE6-8 can support SVG, but only with external plugins with only some of those plugins supporting JavaScript manipulation.
<audio>
and<video>
: are only supported in IE9.Dynamically creating radio buttons: IE <8 has a bug which makes radio buttons created with
document.createElement
uncheckable. See also How do you dynamically create a radio button in Javascript that works in all browsers? for a way to get around this.Embedded JavaScript in
<a href>
tags andonbeforeunload
conflicts in IE: If there's embedded JavaScript in thehref
part of ana
tag (e.g.<a href="javascript: doStuff()">
then IE will always show the message returned fromonbeforeunload
unless theonbeforeunload
handler is removed beforehand. See also Ask for confirm when closing a tab.<script>
tag event differences:onsuccess
andonerror
aren't supported in IE and are replaced by an IE-specificonreadystatechange
which is fired regardless of whether the download succeeded or failed. See also JavaScript Madness for more info.
##Element size/position/scrolling and mouse position:
- Getting element size/position: width/height of elements is sometimes
elm.style.pixelHeight/Width
in IE rather thanelm.offsetHeight/Width
, but neither is reliable in IE, especially in quirks mode, and sometimes one gives a better result than the other.
elm.offsetTop
andelm.offsetLeft
are often incorrectly reported, leading to finding positions of elements being incorrect, which is why popup elements etc are a few pixels off in a lot of cases.Also note that if an element (or a parent of the element) has a
display
ofnone
then IE will raise an exception when accessing size/position attributes rather than returning0
as Firefox does.Get the screen size (Getting the viewable area of the screen):
- Firefox:
window.innerWidth/innerHeight
- IE standards mode:
document.documentElement.clientWidth/clientHeight
- IE quirks mode:
document.body.clientWidth/clientHeight
- Firefox:
Document scroll position/mouse position: This one is actually not defined by the w3c so is non-standard even in Firefox. To find the
scrollLeft
/scrollTop
of thedocument
:Firefox and IE in quirks mode:
document.body.scrollLeft/scrollTop
IE in standards mode:
document.documentElement.scrollLeft/scrollTop
NOTE: Some other browsers use
pageXOffset
/pageYOffset
as well.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]; };
In order to get the position of the mouse cursor,
evt.clientX
andevt.clientY
inmousemove
events will give the position relative to the document without adding the scroll position so the previous function will need to be 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]]; }; };
##Selections/ranges:
<textarea>
and<input>
selections:selectionStart
andselectionEnd
are not implemented in IE, and there's a proprietary "ranges" system in its place, see also How to get the caret column (not pixels) position in a textarea, in characters, from the start?.Getting the currently selected text in the document:
- Firefox:
window.getSelection().toString()
- IE:
document.selection.createRange().text
- Firefox:
##Getting elements by ID:
document.getElementById
can also refer to thename
attribute in forms (depending which is defined first in the document) so it's best not to have different elements which have the samename
andid
. This dates back to the days whenid
wasn't a w3c standard.document.all
(a proprietary IE-specific property) is significantly faster thandocument.getElementById
, but it has other problems as it always prioritizesname
beforeid
. I personally use this code, falling back with additional checks just to be sure: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; }; };
##Problems with read only innerHTML:
IE does not support setting the innerHTML of
col
,colGroup
,frameSet
,html
,head
,style
,table
,tBody
,tFoot
,tHead
,title
, andtr
elements. Here's a function which works around that for table-related elements: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; }; }; };
Also note that IE requires adding a
<tbody>
to a<table>
before appending<tr>
s to that<tbody>
element when creating usingdocument.createElement
, for example: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 differences:
Getting the
event
variable: DOM events aren't passed to functions in IE and are accessible aswindow.event
. One common way of getting the event is to use e.g.elm.onmouseover = function(evt) {evt = evt||window.event}
which defaults towindow.event
ifevt
is undefined.Key event code differences: Key event codes vary wildly, though if you look at Quirksmode or JavaScript Madness, it's hardly specific to IE, Safari and Opera are different again.
Mouse event differences: the
button
attribute in IE is a bit-flag which allows multiple mouse buttons at once:- Left: 1 (
var isLeft = evt.button & 1
) - Right: 2 (
var isRight = evt.button & 2
) - Center: 4 (
var isCenter = evt.button & 4
)
The W3C model (supported by Firefox) is less flexible than the IE model is, with only a single button allowed at once with left as
0
, right as2
and center as1
. Note that, as Peter-Paul Koch mentions, this is very counter-intuitive, as0
usually means 'no button'.offsetX
andoffsetY
are problematic and it's probably best to avoid them in IE. A more reliable way to get theoffsetX
andoffsetY
in IE would be to get the position of the relatively positioned element and subtract it fromclientX
andclientY
.Also note that in IE to get a double click in a
click
event you'd need to register both aclick
anddblclick
event to a function. Firefox firesclick
as well asdblclick
when double clicking, so IE-specific detection is needed to have the same behaviour.- Left: 1 (
Differences in the event handling model: Both the proprietary IE model and the Firefox model support handling of events from the bottom up, e.g. if there are events in both elements of
<div><span></span></div>
then events will trigger in thespan
then thediv
rather than the order which they're bound if a traditional e.g.elm.onclick = function(evt) {}
was used."Capture" events are generally only supported in Firefox etc, which will trigger the
div
then thespan
events in a top down order. IE haselm.setCapture()
andelm.releaseCapture()
for redirecting mouse events from the document to the element (elm
in this case) before processing other events, but they have a number of performance and other issues so should probably be avoided.Firefox:
Attach:
elm.addEventListener(type, listener, useCapture [true/false])
Detach:elm.removeEventListener(type, listener, useCapture)
(type
is e.g.'mouseover'
without theon
)IE: Only a single event of a given type on an element can be added in IE - an exception is raised if more than one event of the same type is added. Also note that the
this
refers towindow
rather than the bound element in event functions (so is less useful):Attach:
elm.attachEvent(sEvent, fpNotify)
Detach:elm.detachEvent(sEvent, fpNotify)
(sEvent
is e.g.'onmouseover'
)
Event attribute differences:
Stop events from being processed by any other listening functions:
Firefox:
evt.stopPropagation()
IE:evt.cancelBubble = true
Stop e.g. key events from inserting characters or stopping checkboxes from getting checked:
Firefox:
evt.preventDefault()
IE:evt.returnValue = false
Note: Just returningfalse
inkeydown
,keypress
,mousedown
,mouseup
,click
andreset
will also prevent default.Get the element which triggered the event:
Firefox:
evt.target
IE:evt.srcElement
Getting the element the mouse cursor moved away from:
evt.fromElement
in IE isevt.target
in Firefox if in anonmouseout
event, otherwiseevt.relatedTarget
Getting the element the mouse cursor moved to:
evt.toElement
in IE isevt.relatedTarget
in Firefox if in anonmouseout
event, otherwiseevt.target
Note:
evt.currentTarget
(the element to which the event was bound) has no equivalent in IE.
这篇关于在 Firefox 上开发的 Javascript 在 IE 上失败的典型原因是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文登录 关闭
扫码关注1秒登录发送“验证码”获取 | 15天全站免登陆