JavaScript 操作 DOM 的那些坑

js在操作DOM中存在着许多跨浏览器方面的坑,本文花了我将近一周的时间整理,我将根据实例整理那些大大小小的“坑”。

DOM的工作模式是:先加载文档的静态内容、再以动态方式对它们进行刷新,动态刷新不影响文档的静态内容。

PS:IE 中的所有 DOM 对象都是以 COM 对象的形式实现的,这意味着 IE 中的 DOM可能会和其他浏览器有一定的差异。

Node 接口

特性/方法 类型/返回类型 说 明
nodeName String 节点的名字;根据节点的类型而定义
nodeValue String 节点的值;根据节点的类型而定义
nodeType Number 节点的类型常量值之一
ownerDocument Document 返回某元素的根元素
firstChild Node 指向在childNodes列表中的第一个节点
lastChild Node 指向在childNodes列表中的最后一个节点
childNodes NodeList 所有子节点的列表
previousSibling Node 返回选定节点的上一个同级节点,若不存在,则返回null
nextSibling Node 返回被选节点的下一个同级节点,若不存在,则返回null
hasChildNodes() Boolean 如果当前元素节点拥有子节点,返回true,否则返回false
attributes NamedNodeMap 返回包含被选节点属性的 NamedNodeMap
appendChild(node) node 将node添加到childNodes的末尾
removeChild(node) node 从childNodes中删除node
replaceChild(newnode, oldnode) Node 将childNodes中的oldnode替换成newnode
insertBefore Node 在已有子节点之前插入新的子节点

firstChild 相当于 childNodes[0]lastChild 相当于childNodes[box.childNodes.length - 1]

nodeType返回结点的类型

innerHTML 和 nodeValue

两者区别

nodeName属性获得结点名称

tagName

getElementsByTagName()方法将返回一个对象数组 HTMLCollection(NodeList),这个数组保存着所有相同元素名的节点列表。

PS:IE 浏览器在使用通配符的时候,会把文档最开始的 html 的规范声明当作第一个元素节点。

节点的绝对引用:

节点的相对引用:(设当前对节点为node)

节点信息

创建新节点

获取鼠标点击事件的位置

以下所描述的属性在chromeSafari 都很给力的支持了。

问题一:FirefoxChromeSafariIE9都是通过非标准事件的pageXpageY属性来获取web页面的鼠标位置的。pageX/Y获取到的是触发点相对文档区域左上角距离,以页面为参考点,不随滑动条移动而变化

问题二:在IE 中,event 对象有 x, y 属性(事件发生的位置的 x 坐标和 y 坐标)火狐中没有。在火狐中,与event.x 等效的是event.pageXevent.clientXevent.pageX 有微妙的差别(当整个页面有滚动条的时候),不过大多数时候是等效的。

offsetX:IE特有,chrome也支持。鼠标相比较于触发事件的元素的位置,以元素盒子模型的内容区域的左上角为参考点,如果有boder,可能出现负值

问题三:
scrollTop为滚动条向下移动的距离,所有浏览器都支持document.documentElement

其余参照:http://segmentfault.com/a/1190000002559158#articleHeader11

参照表

+为支持,-为不支持):

查看下方DEMO
你会发现offsetXFirefox下是undefined,在chromeIE则会正常显示。

https://jsfiddle.net/f4am208m/embedded/result/

2232231280-553f23779b846_articlex

offsetLeft和style.left区别

getComputedStyle与currentStyle

getComputedStyle()接受两个参数:要取得计算样式的元素和一个伪元素,如果不需要伪元素,则可以是null。然而,在IE中,并不支持getComputedStyle,IE提供了currentStyle属性。

getComputedStyle(obj , false ) 是支持 w3c (FF12、chrome 14、safari):在FF新版本中只需要第一个参数,即操作对象,第二个参数写“false”也是大家通用的写法,目的是为了兼容老版本的火狐浏览器。
缺点:在标准浏览器中正常,但在IE6/7/8中不支持

取消表单提交

确定浏览器窗口的尺寸

对于主流浏览器来说,比如IE9FirefoxChromeSafari,支持名为innerWidthinnerHeight的窗口对象属性,它返回窗口的视口区域,减去任何滚动条的大小。IE不支持innerWidthinnerHeight

实用的 JavaScript 方案(涵盖所有浏览器):

对于 IE 6、7、8的方案如下:

或者

Document对象的body属性对应HTML文档的<body>标签。Document对象的documentElement属性则表示 HTML文档的根节点。

attributes 属性

attributes 属性返回该节点的属性节点集合。

setAttribute 和 getAttribute

IE中是不认识class属性的,需改为className属性,同样,在Firefox中,也是不认识className属性的,Firefox只认识class属性,所以通常做法如下:

IE:可以使用获取常规属性的方法来获取自定义属性,也可以使用getAttribute()获取自定义属性
Firefox:只能使用getAttribute()获取自定义属性.

解决方法:统一通过getAttribute()获取自定义属性

PS:在 IE7 及更低版本的IE浏览器中,使用 setAttribute()方法设置 classstyle 属性是没有效果的,虽然 IE8 解决了这个bug,但还是不建议使用。

removeAttribute()方法

PS:IE6 及更低版本不支持 removeAttribute()方法。

跨浏览器事件Event对象

dataTransfer 对象

| 属性 | 描述 |
| ————- |:————-:|
| dropEffect | 设置或获取拖曳操作的类型和要显示的光标类型 |
| effectAllowed | 设置或获取数据传送操作可应用于该对象的源元素 |

| 方法 | 描述 |
| ————- |:————-:|
| clearData | 通过 dataTransfer 或 clipboardData 对象从剪贴板删除一种或多种数据格式 |
| getData | 通过 dataTransfer 或 clipboardData 对象从剪贴板获取指定格式的数据
| setData | 以指定格式给 dataTransfer 或 clipboardData 对象赋予数据

HTML5拖拽的浏览器支持

Internet Explorer 9、Firefox、Opera 12、Chrome 以及 Safari 5 支持拖放

为了使元素可拖动,需把 draggable 属性设置为 true

| 事件 | 描述 |
| ————- |:————-:|
| dragstart | 拖拽事件开始 |
| drag | 在拖动操作上 |
| dragenter | 拖动到目标上,用来决定目标是否接受放置
|dragover | 拖动到目标上,用来决定给用户的反馈
|drop | 放置发生
| dragleave| 拖动离开目标
|dragend | 拖动操作结束

上述代码的一些浏览器兼容性:

跨浏览器获取目标对象

对于获取触发事件的对象,w3cIE也有不同的做法:

我们可以使用三目运算符来兼容他们:

innerText的问题

innerTextIE中能正常工作,但是innerTextFireFox中却不行。

跨浏览器获取和设置innerText

oninput,onpropertychange,onchange的用法

onchange触发事件必须满足两个条件:

onpropertychange的话,只要当前对象属性发生改变,都会触发事件,但是它是IE专属的;

访问XMLHTTPRequest对象

禁止选取网页内容

三大不冒泡事件

所有浏览器的focus/blur事件都不冒泡,万幸的是大部分浏览器支持focusin/focusout事件,不过可恶的firefox连这个都不支持。

万恶的滚轮事件

滚轮事件的支持可谓是乱七八糟,规律如下:

关于鼠标滚轮事件,IE支持mousewheel,火狐支持DOMMouseScroll
判断鼠标滚轮是向上还是向下,IE是通过wheelDelta属性,而火狐是通过detail属性

事件委托方法

HTML5 的浏览器支持情况

1110813980-55349a9f5d0b8_articlex

1656139665-55349ae36c519_articlex

来源地址:http://fmbip.com/litmus/

查询操作

查询通过指的是通过一些特征字符串来找到一组元素,或者判断元素是不是满足字符串。

  1. IE6/7不区分id和nam在IE6/7下使用getElementById和getElementsByName时会同时返回id或name与给定值相同的元素。由于name通常由后端约定,因此我们在写JS时,应保证id不与name重复。
  2. IE6/7不支持getElementsByClassName和querySelectorAll 这两个函数从IE8开始支持的,因此在IE6/7下,我们实际可以用的只有getElementByTagName。
  3. IE6/7不支持getElementsByTagName(‘*’)会返回非元素节点 要么不用*,要么自己写个函数过滤一下。
  4. IE8下querySelectorAll对属性选择器不友好 几乎所有浏览器预定义的属性都有了问题,尽量使用自定义属性或者不用属性选择器。
  5. IE8下querySelectorAll不支持伪类 有时候伪类是很好用,IE8并不支持,jquery提供的:first、:last、:even、:odd、:eq、:nth、:lt、:gt并不是伪类,我们在任何时间都不要使用它们。
  6. IE9的matches函数不能处理不在DOM树上的元素只要元素不在dom树上,一定会返回false,实在不行把元素丢在body里面匹配完了再删掉吧,当然了我们也可以自己写匹配函数以避免回流。1427561864-55278e3dc5c4e_articlex

资料参考:

http://w3help.org/zh-cn/kb/
http://www.zhihu.com/question/29072028

1 15 收藏 1 评论

可能感兴趣的话题



直接登录
最新评论
跳到底部
返回顶部