Document.defaultView
Document.defaultView
引子
最近愚安在写一个可以将页面上的资源链接转为二维码以方便移动端浏览的chrome插件,由于dom操作并不多,而且作为插件不需要考虑跨
浏览器兼容性,所以并没有引入jQuery,而是使用原生的DOM API
。其中有一个需求是判断元素在页面上的相对文档的偏移offset。我使用
的方法如下:
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)
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
对象有什么不同呢?
控制台查看
document.defaultView === window
//true
靠,这有什么意义呢,是jQuery的装B写法么?
查看DOM API文档
打开MDN,我找到了关于defaultView
的描述
,稍翻一下
Document.defaultView
概要:
在浏览器中返回关联document的window对象,如果没有则返回null
用法:
var win = document.defaultView;
这是一个只读属性。
注意:
在quirksmode模式下, IE 9 以下版本不支持defaultView.
测试
好了,既然有这么个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.html
<html>
<head>
</head>
<body>
<p>I'm iFrame</p>
<script>
console.log(window === document.defaultView);
</script>
</body>
</html>
测试结果:true
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的出现,还真是里程碑意义的事件,他极大力度的解放了前端的生产力,让前端开发人员,
有时间和精力去开发各种前端工具,规范,才有了大前端时代的来临。哈哈,吹的有点多,干货略少。
作者:愚安
出处:http://www.cnblogs.com/yuan-shuai/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。