JavaScript 操作 DOM 的那些坑

發表於2016-09-26

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

相關文章