本篇主要记录一下昨天和同事对JQ里取绝对像素值时对runTimeStyle的一处细节的讨论,同时提出自己的一些疑问。
疑问
最近我的同事 小卡 在整合jquery代码的时候,对JQuery里IE下取精确像素值的部分提出了一些疑问
下面的代码片段来自jquery-1.8.2.js:
currentStyle = function( elem, name ) {
var left, rsLeft, uncomputed,
ret = elem.currentStyle && elem.currentStyle[ name ],
style = elem.style;
// Avoid setting ret to empty string here
// so we don't default to auto
if ( ret == null && style && (uncomputed = style[ name ]) ) {
ret = uncomputed;
}
// From the awesome hack by Dean Edwards
// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
// If we're not dealing with a regular pixel number
// but a number that has a weird ending, we need to convert it to pixels
if ( rnumnonpx.test( ret ) ) {
// Remember the original values
//①
left = style.left;
rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
// Put in the new values to get a computed value out
//②
if ( rsLeft ) {
elem.runtimeStyle.left = elem.currentStyle.left;
}
//③
style.left = name === "fontSize" ? "1em" : ret;
ret = style.pixelLeft + "px";
// Revert the changed values
//④
style.left = left;
if ( rsLeft ) {
elem.runtimeStyle.left = rsLeft;
}
}
return ret === "" ? "auto" : ret;
};
主要是代码段②这里
// Put in the new values to get a computed value out
if ( rsLeft ) {
elem.runtimeStyle.left = elem.currentStyle.left; //疑问!
}
疑问:这一句到底是干啥用的?
小卡试过 将这段去掉,在IE6/7/8/9里均不影响最终结果,即使runtimeStyle已经被人为设置过
解释?
我以前看JQ的时候也对DE的这段代码有过疑问,所以我按照那时候的理解给出的解释:
runtimeStyle是运行时样式,优先级最高
- 当runtimeStyle有值的时候,元素实际渲染总是以此为准,此时:
- 若用js取currentStyle的值时,引擎会返回runtimeStyle的值
- 若去设置style,元素的实际渲染不会发生变化的,因为style优先级很低,已经不作数了
- 当runtimeStyle的值不存在或者被清空(赋值''就是清空)时,元素的渲染以currentStyle为准。此时:
- 用js取currentStyle的值,就按照currentStyle自己的规则得到值。(currentStyle取值按照import-style,inline-style,HTML Attribute,HTML default根据样式优先级决定)
- 若去设置style,则有可能改变元素的渲染
所以结合JQ的代码来看:
①是备份style和runtimeStyle(因为后面需要还原)
②是一个必要的副作用消除步骤,因为接下来要通过设置style来取像素值,这里给最高优先级的runtimeStyle设置currentStyle,就能保证下面的过程不改变渲染
③是通过设置style.left然后再通过pixelLeft取像素值的过程
④是还原现场的过程
但 herbert 提出了质疑:
写道
如果runtimeStyle存在的话,currentStyle的值一定是runtimeStyle的值,这里赋值的意义何在?
我回过头看了一下上面的代码,发现还真是这么回事。
if ( rsLeft ) {
//进了这个if,说明runtimeStyle.left有值
//当runtimeStyle.left有值时, currentStyle.left的值取出来就是runtimeStyle.left的值
//那下面这句赋值确实无意义啊!囧囧囧~~
elem.runtimeStyle.left = elem.currentStyle.left;
}
为啥我以前研究这里的时候,没发现这个悖论呢?
溯源-反省
去找了下源头:

发现DE原始的代码里并无此判断
然后又翻了一下1.4的JQ,发现里面也是没有这句判断。
发现是1.5版本才增加的这个判断。
那么到底JQ里为啥要增加这句判断呢?
去Github看下history,发现2011年1月5号之前,源码里也是没有这个判断的
直到rwldrn一个针对opera的
bugfix
:

可以看到,这里是为了规避opera抛出异常,所以加了一句判断。
看到这里,只有两种可能性了:
A. 我之前的理解是错误的,这里并非为了担心下面对style.left赋值导致UI改变才写了这句话,而是有其他我暂未想到的原因
B. 我之前的理解是正确的,rwldrn的这个fix虽然规避了异常,但无意间使得对runtimeStyle的设置和恢复的代码,在常规情况下都不会进入了
那个可能性更大?
rwldrn提交了一个有副作用的fix(尽管可以看到,这个副作用不大),而这个错误在接下来的2年里,在无数人review的JQuery项目里,都未被发现?
所以我更倾向于我的理解是错误的。
到底咋解释?
再看一遍runTimeStyle的
资料
:
仍然没有思路
在网上找了一圈下来,发现大部分的理解和我基本相同
...
其中要提的是 element.runtimeStyle 为什么这里也把他临时覆盖了呢? 可能是出于 保险。比如 其他代码中可能更改了此值 因为 runtimeStyle的优先级 要高越style... 所以为了pixelLeft取出正确的值 所以 也覆盖了element.runtimeStyle.
...
其中要提的是 element.runtimeStyle 为什么这里也把他临时覆盖了呢? 可能是出于 保险。比如 其他代码中可能更改了此值 因为 runtimeStyle的优先级 要高越style... 所以为了pixelLeft取出正确的值 所以 也覆盖了element.runtimeStyle.
...
franky的这个猜测,倒是和我的理解不同,但他的博文较早了,当时也仍然是基于没有那句if的讨论,所以当时看来也说得通
但现在jq里加上那句if后,这个解释仍然无法规避同样的悖论
实在想不出什么靠谱的解释了。。。
只能先上来po一篇博文,留待以后研究后补充结论。
也欢迎大神们来这里讨论~~
相关资料
汇总在这里(持续补充),供参考:
来源:
http://erik.eae.net/archives/2007/07/27/18.54.15/
两篇相关的中文blog:
http://yiminghe.iteye.com/blog/511589
http://www.cnblogs.com/_franky/archive/2009/11/29/1612969.html
runtimeStyle属性的介绍:
http://help.dottoro.com/ljhddfwr.php
http://erik.eae.net/archives/2007/07/27/18.54.15/
两篇相关的中文blog:
http://yiminghe.iteye.com/blog/511589
http://www.cnblogs.com/_franky/archive/2009/11/29/1612969.html
runtimeStyle属性的介绍:
http://help.dottoro.com/ljhddfwr.php


被折叠的 条评论
为什么被折叠?



