最近愚安在寫一個能夠將頁面上的資源連接轉爲二維碼以方便移動端瀏覽的chrome插件,因爲dom操做並很少,並且做爲插件不須要考慮跨
瀏覽器兼容性,因此並無引入jQuery,而是使用原生的DOM API
。其中有一個需求是判斷元素在頁面上的相對文檔的偏移offset。我使用
的方法以下:javascript
function getOffset(ele){ if (!ele || ele.nodeType != 1) { return; } var rect = ele.getBoundingClientRect(), doc = ele.ownerDocument.documentElement; return { top: rect.top + window.pageYOffset - doc.clientTop, left: rect.left + window.pageXOffset - doc.clientLeft }; }
由於之前看過一點jQuery的源碼,又不須要注意兼容,因此寫起來仍是比較順手的。這個方法,寫出來還算是挺好用的,沒發現什麼問題,
得意之時,想着,要不去看下jQuery是怎麼寫的,翻了下,源碼以下(version 2.1.1)html
offset: function(options) { if (arguments.length) { return options === undefined ? this : this.each(function(i) { jQuery.offset.setOffset(this, options, i); }); } var docElem, win, elem = this[0], box = { top: 0, left: 0 }, doc = elem && elem.ownerDocument; if (!doc) { return; } docElem = doc.documentElement; // Make sure it's not a disconnected DOM node if (!jQuery.contains(docElem, elem)) { return box; } // If we don't have gBCR, just use 0,0 rather than error // BlackBerry 5, iOS 3 (original iPhone) if (typeof elem.getBoundingClientRect !== strundefined) { box = elem.getBoundingClientRect(); } win = getWindow(doc); return { top: box.top + win.pageYOffset - docElem.clientTop, left: box.left + win.pageXOffset - docElem.clientLeft }; }
看了下,除了一些兼容性處理,和一些對jQuery對象的操做外,基本和個人作法是同樣的,哈哈哈!忽然瞄到了這麼個東西win = getWindow(doc)
,
趕忙看下源碼前端
function getWindow(elem) { return jQuery.isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView; }
ちょっと待って,defaultView
是什麼東西呢,咱們知道nodeType爲9時,該元素就是document
,因爲以前沒有使用過,
document.defaultView
的結果和我代碼裏的window
對象有什麼不一樣呢?java
document.defaultView === window //true
靠,這有什麼意義呢,是jQuery的裝B寫法麼?node
打開MDN,我找到了關於defaultView
的描述
,稍翻一下chrome
Document.defaultView
概要:
在瀏覽器中返回關聯document的window對象,若是沒有則返回null
用法:
var win = document.defaultView;
這是一個只讀屬性。
注意:
在quirksmode模式下, IE 9 如下版本不支持defaultView.api
好了,既然有這麼個API天然是有他的用途的,MDN的文檔表示defaultView是document關聯的window對象,那麼其用途確定體如今當前上下文的window
不等於當前document關聯的window時,即window !== document.defaultView
,那麼什麼上下文(context)會出現這種狀況呢,我想到了三種:
1.frame;2.popup;3.extension
開測:
1.frame
index.html瀏覽器
<html> <head> </head> <body> <iframe src="frame.html" id="myframe" name="myframe"> </iframe> <script> </script> </body> </html>
frame.htmlless
<html> <head> </head> <body> <p>I'm iFrame</p> <script> console.log(window === document.defaultView); </script> </body> </html>
測試結果:truedom
2.pupup
var open = window.open('frame.html');
測試結果:true
3.extension
在我寫的這個chromePlugin裏我分別在background.js和content.js裏測試
無一例外window === document.defaultView
都返回true。
這時我想到了firefox的擴展,但本身沒有開發FF擴展的經驗,就去google了一下,發現了這個,
大體意思是說,「若是你的擴展運行在FireFox 31如下的版本,在content.js裏必須使用document.defaultView.postMessage」。
看到這裏,我突然想起jQuery源碼中的defaultView也許就是爲了兼容某些Firefox版本,哈哈,繼續Google
終於,讓我在MDN上找到了這個傳送門
In many code samples online, getComputedStyle is used from the document.defaultView object. In nearly all cases, this is needless, as getComputedStyle exists on the window object as well. It's likely the defaultView pattern was some combination of (1) folks not wanting to write a spec for window and (2) making an API that was also usable in Java. However, there is a single case where the defaultView's method must be used: when using Firefox 3.6 to access framed styles.
很顯然,坑就在這裏了,當使用Firefox 3.6時,其frame中須要使用document.defaultView去獲取window對象,才能使用其getComputedStyle方法。
好了,這個問題告一段落。
不止一次聽人抱怨jQuery的代碼是多麼的糟(qiang)糕(da),其運用大量的黑魔法,各類奇技淫巧去兼容全部的瀏覽器,即便已到2.1.1版本,仍然保持着對FF低版本的支持。 想一想看在那個前端開發,還處在蠻荒的時代,jQuery的出現,還真是里程碑意義的事件,他極大力度的解放了前端的生產力,讓前端開發人員, 有時間和精力去開發各類前端工具,規範,纔有了大前端時代的來臨。哈哈,吹的有點多,乾貨略少。