文章目录
  1. 1. offset兼容性与定时器
    1. 1.1. 1、offset兼容性:
    2. 1.2. 2、定时器

offset兼容性与定时器

1、offset兼容性:

offsetParent : 离当前节点最近的具有定位属性的祖先节点。

如果所有祖先节点都没有定位属性:
对于一个有定位属性的元素:
ie6、7 : offsetParent 是 html 节点
其它浏览器: offsetParent 是 body 节点

对于一个没有定位的元素:
  ie6/7 : 最近的一个触发了 haslayout 属性的祖先节点,如果所有祖先节点都没有触发 haslayout ,默认为 body 节点。
  其它浏览器: body。

如果当前节点有 display:none; 属性 在 ie11 以上及标准浏览器,offsetParent为null,ie10以下浏览器不受影响。

回流 、重绘
offsetLeft : 当前节点左边到 offsetParent 左边的距离。

offsetTop : 当前节点上边到 offsetParent 上边的距离。

注意:
1、如果body和html有边框和外边距, offsetLeft 和 offsetTop 在所有浏览器下的取值都会不一样。

2、在ie6、7浏览器下 ,offsetLeft和offsetTop会计算 offsetParent 的边框值,其它浏览器不会计算边框值。

3、如果当前节点设置了 display: none; 属性,offsetLeft 和 offsetLeft 的值都为0.(ie6/7下为 -1)。

2、定时器

setTimeout 和 setInterval

由于 JavaScript 是异步的,可以使用 setTimeout 和 setInterval 来计划执行函数。

基于 JavaScript 引擎的计时策略,以及本质上的单线程运行方式,所以其它代码的运行可能会阻塞此线程。 因此没法确保函数会在 setTimeout 指定的时刻被调用。

作为第一个参数的函数将会在全局作用域中执行,因此函数内的 this 将会指向这个全局对象。

1
2
3
4
5
6
7
8
9
function Foo() {
this.value = 42;
this.method = function() {
// this 指向全局对象
console.log(this.value); // 输出:undefined
};
setTimeout(this.method, 500);
}
new Foo();

注意: setTimeout 的第一个参数是函数对象,一个常犯的错误是这样的 setTimeout(foo(), 1000), 这里回调函数是 foo 的返回值,而不是foo本身。 大部分情况下,这是一个潜在的错误,因为如果函数返回 undefined,setTimeout 也不会报错。
setInterval 的堆调用
setTimeout 只会执行回调函数一次,不过 setInterval - 正如名字建议的 - 会每隔 X 毫秒执行函数一次。 但是却不鼓励使用这个函数。

当回调函数的执行被阻塞时,setInterval 仍然会发布更多的回调指令。在很小的定时间隔情况下,这会导致回调函数被堆积起来。

1
2
3
4
5

function foo(){
// 阻塞执行 1 秒
}
setInterval(foo, 1000);

上面代码中,foo 会执行一次随后被阻塞了一秒钟。

在 foo 被阻塞的时候,setInterval 仍然在组织将来对回调函数的调用。 因此,当第一次 foo 函数调用结束时,已经有 10 次函数调用在等待执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
	var oCurrent=document.getElementById('current');
var timer=null;
function appear(){
var oCurrent=document.getElementById('current');
clearInterval(timer); //避免定时器叠加(即每次触动时右再开一个定时器)
timer=setInterval(function appearBlock(){
if(oCurrent.offsetLeft<=1120)
{
clearInterval(timer);
}
else{
oCurrent.style.left=oCurrent.offsetLeft-30+'px';
}
},30);
}
function out(){
var oCurrent=document.getElementById('current');
clearInterval(timer); //避免定时器叠加(即每次触动时右再开一个定时器)
timer=setInterval(function appearBlock(){
if(oCurrent.offsetLeft>=1325)
{
clearInterval(timer);
}
else{
oCurrent.style.left=oCurrent.offsetLeft+30+'px';
}
},30);
}

处理可能的阻塞调用
最简单也是最容易控制的方案,是在回调函数内部使用 setTimeout 函数。

1
2
3
4
5
function foo(){
// 阻塞执行 1 秒
setTimeout(foo, 1000);
}
foo();

这样不仅封装了 setTimeout 回调函数,而且阻止了调用指令的堆积,可以有更多的控制。 foo 函数现在可以控制是否继续执行还是终止执行。

手工清空定时器
可以通过将定时时产生的 ID 标识传递给 clearTimeout 或者 clearInterval 函数来清除定时, 至于使用哪个函数取决于调用的时候使用的是 setTimeout 还是 setInterval。

var id = setTimeout(foo, 1000);
clearTimeout(id);

清除所有定时器
由于没有内置的清除所有定时器的方法,可以采用一种暴力的方式来达到这一目的。
可以事先保存所有的定时器 ID,然后一把清除。

隐藏使用 eval
setTimeout 和 setInterval 也接受第一个参数为字符串的情况。 这个特性绝对不要使用,因为它在内部使用了 eval。

注意: 由于定时器函数不是 ECMAScript 的标准,如何解析字符串参数在不同的 JavaScript 引擎实现中可能不同。 事实上,微软的 JScript 会使用 Function 构造函数来代替 eval 的使用。
function foo() {
// 将会被调用
}

function bar() {
    function foo() {
        // 不会被调用
    }
    setTimeout('foo()', 1000);
}
bar();

由于 eval 在这种情况下不是被直接调用,因此传递到 setTimeout 的字符串会自全局作用域中执行; 因此,上面的回调函数使用的不是定义在 bar 作用域中的局部变量 foo。

建议不要在调用定时器函数时,为了向回调函数传递参数而使用字符串的形式。

function foo(a, b, c) {}

// 不要这样做
setTimeout('foo(1,2, 3)', 1000)

// 可以使用匿名函数完成相同功能
setTimeout(function() {
    foo(1, 2, 3);
}, 1000)

注意:
1、使用定时器setInterval()或者setTimeout()前需清除定时器;
2、定时处理不是 ECMAScript 的标准,它们在 DOM (文档对象模型)被实现;
3、绝对不要使用字符串作为 setTimeout 或者 setInterval 的第一个参数,这么写的代码明显质量很差。当需要向回调函数传递参数时,可以创建一个匿名函数,在函数内执行真实的回调函数。

文章目录
  1. 1. offset兼容性与定时器
    1. 1.1. 1、offset兼容性:
    2. 1.2. 2、定时器