【DOM编程艺术】实时动画---幻灯片

onmouseover事件被触发时显示一张图片。我们将沿用图片库案例中的脚本----只需把每个链接上的事件处理函数从onclikc改为onmouseover。它能工作,但图片显示得不够流畅:当用户第一次把鼠标指针悬停在某个链接上时,新图片将被加载过去。

即使实在一个高速的网络连接上,这多少也需要花费点儿时间,而我们希望能够立刻响应。

解决问题:如果为每个链接分别准备一张预览图片,在切换显示这些图片时总会有一些延迟。除此之外,简单地切换显示这些图片也不是我们期望的效果。我们想要的是一种更快更好的东西。

     下面是我们要做的事情。

      ■ 为所有的预览图片生成为一张"集体照"形式的图片。

      ■ 隐藏这张"集体照"图片的绝大部分。

      ■ 当用户把鼠标指针悬停在某个链接的上方时,只显示这张"集体照"图片的相应部分。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Web Design</title>
<style type="text/css">
#slideshow{width:100px; height:100px; position:relative; overflow:hidden;}
</style>
</head>

<body>
<h1>Web Design</h1>
<p>These are the things you should know.</p>
<ol id='linklist'>
    <li><a href="structure.html">Structure</a></li>
    <li><a href="presentation.html">Presentation</a></li>
    <li><a href="behavior.html">Behavior</a></li>
</ol>
<div id='slideshow'>
    <img src="images/topics.gif"  alt='building blocks of web design' id='preview' />
</div>
<script>
window.onload = prepareSlideshow;
function prepareSlideshow(){
    /*为图片应用样式*/
    var preview = document.getElementById('preview');
    preview.style.position = 'absolute';
    preview.style.left = '0px';
    preview.style.top = '0px';
    var list = document.getElementById('linklist');
    var item = list.getElementsByTagName('a');
    item[0].onmouseover = function(){
          moveElement('preview',-100,0,10);
    }
    item[1].onmouseover = function(){
          moveElement('preview',-200,0,10);
    }
    item[2].onmouseover = function(){
          moveElement('preview',-300,0,10);
    }
}
function moveElement(elementId,final_x,final_y,interval){
    if( !document.getElementById) return false;
    if( !document.getElementById(elementId)) return false;
    var elem = document.getElementById(elementId);
    if(elem.movement){
        clearTimeout(elem.movement);
    }
    var xpos = parseInt(elem.style.left);
    var ypos = parseInt(elem.style.top);
    if(xpos == final_x && ypos == final_y){
        return true;
    }
    if(xpos < final_x){
        xpos++;
    }
    if(xpos > final_x){
        xpos--;
    }
    if(ypos < final_y){
        ypos++;
    }
    if(ypos > final_y){
        ypos--;
    }
    elem.style.left = xpos +'px';
    elem.style.top = ypos +'px';
    var repeat="moveElement('"+elementId+"',"+final_x+","+final_y+","+interval+")";
    elem.movement=setTimeout(repeat,10);
}

</script>
</body>
</html>

 绿色代码不存在的情况下,事情好像有点不太对头:如果把鼠标指针在链接之间快速地来回移动,动画效果将变得混乱起来。

解析:动画效果不正确的问题是由一个全局变量引起的。

   这留下了一个隐患:每当用户把鼠标指针悬停在某个链接上,不管上一次调用是否已经把图片移动到位,moveElement函数都会被再次调用并试图把这个图片移动到另一个地方去。于是,当用户在链接之间快速移动鼠标时,movement变量就会像

            一条拔河绳那样来回变化,而moveElement函数就会试图把图片同时移动到两个不同的地方去。

   如果用户移动鼠标的速度够快,积累在setTimeout队列里的事件就会导致动画效果产生滞后。为了消除动画滞后的现象,可以用clearTimeout消除积累在setTimeout队列里的事件:

   clearTimeout(movement);

   可是,如果在还没有设置movement变量之前就执行这条语句,我们会收获一个错误。

   我不能使用局部变量:var movement = setTimeout(repeat,interval);

   如果这样做,clearTimeout函数调用语句将无法工作,因为局部变量movement在clearTimeout函数的上下文里不存在。

     也就是说,既不能使用全局变量,也不能使用局部变量。我们需要一种介乎它们二者之间的东西,需要一个只与正在被移动的那个元素有关的变量。

   只与某个特定元素有关的变量是存在的。事实上,我们一直在使用它们。那就是"属性"。

   到目前为止,我们一直在使用由DOM提供的属性,如element.firstChild、elemen.style等等。Javascript允许我们为元素创建属性:element.property = value;

   例:element.foo = 'bar'; 这很像是在创建一个变量,但区别是这个变量专属于某个特定的元素。

   我们把变量movement从一个全局变量改变为正在被移动的那个元素(elem元素)的属性。

最终效果:于是,不管moveElement函数正在移动的是哪个元素,该元素都将获得一个名为movement的属性。如果该元素在moveElement函数开始执行时已经有了一个movement属性,就应该用clearTimeout函数对它进行复位。

              这样一来,即使因为用户快速移动鼠标指针而使得某个元素需要向不同的方向移动,实际执行的也只有一条setTimeout函数调用语句。

posted @ 2014-04-22 17:25  Western Journey  阅读(264)  评论(0编辑  收藏  举报