• javascript Dom 编程艺术:ANIMATED SLIDESHOW


    Animation is the perfect example of this kind of change. In a nutshell, animation involves
    changing an element’s position over time.

    Increments
    Moving an element by 150 pixels after an interval of five seconds is a sort of animation,
    albeit a very primitive one. Effective animation uses incremental movement. Moving from
    the starting position to the final location should happen in a series of steps rather than
    one quick jump.

    function moveElement 函数如下:

    function moveElement(elementID,final_x,final_y,interval)
    {
        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,interval);
    }

    为什么用elem.style.top,left始终为Nan,看文章:

    一个非常好的实用的函数。

    "moveElement('"+elementID+"',"+final_x+","+final_y+","+interval+")"
      That’s a lot of concatenating! Rather than inserting that long string directly into the setTimeout function, assign the string to a variable called repeat.
    var repeat ="moveElement('"+elementID+"',"+final_x+","+final_y+","+interval+")";
    Now you can simply insert repeat as the first argument of the setTimeout function. The
    second argument is the length of the pause before the first argument is called. This used
    to be hardcoded as ten milliseconds. Now it’s whatever value is contained by the variable
    interval:
    movement = setTimeout(repeat,interval);
    Close the function with a curly brace:

    要创建一个类式下面的demo:

    当鼠标在链接上面时,下面的图片会滚动到相应的图片。

    Make a composite image of all the previews 一张总图片。
    Hide most of this image
    When the user hovers over a link, display just a part of the image
    I’ve made a composite image of the three previews plus one default view:

    这张总图片叫topics.gif,我们想要当鼠标over link时,只显示图片的一部分。

    <!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>无标题文档</title>
    </head>
    
    <body>
    </body>
    </html>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
    <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>Web Design</title>
    </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>
    
    <img src="topics.gif" alt="building blocks of web design"  id="preview" />
    </body>
    </html>

    Right now, the entire image is visible. I only want a 100 by 100 pixel portion to be visible
    at any one time. I can’t do that with JavaScript, but I can do it with CSS.

    CSS
    The CSS overflow property dictates how content within an element should be displayed
    when the content is larger than its container element. When an element contains content
    that is larger than itself, there is an overflow. In that situation, you can clip the content so
    that only a portion of it is visible. You can also specify whether or not the web browser
    should display scroll bars, allowing the user to see the rest of the content.
    There are four possible values for the overflow property: “visible”, “hidden”, “scroll”, and
    “auto”.
    If the overflow of an element is set to “visible”, then no clipping occurs. The content
    overflows and is rendered outside the element.
    A value of “hidden” will cause the excess content to be clipped. Only a portion of
    the content will be visible.
    The “scroll” value is similar to “hidden”. The content will be clipped but the web
    browser will display scroll bars so that the rest of the content can be viewed.
    A value of “auto” is just like “scroll” except that the scroll bars will only be displayed
    if the content overflows its container element. If there is no overflow, no
    scroll bars appear.
    Of these four values, “hidden” sounds like the most promising for my purposes. I want to
    display just a 100 by 100 pixel (100*100像素)portion of an image that is 400 by 100 pixels in size.

    把图片包围在一个div里:

    <div id="slideshow">
    <img src="topics.gif" alt="building blocks of web design"  id="preview" />
    </div>

    样式表如下:

    <style type="text/css">
    #slideshow{
        width:100px;
        height:100px;
        position:relative;
        overflow:hidden;
    }
    </style>

    Now only a portion of topics.gif is visible. Currently, only the first 100 pixels are visible.

    <script>
    function moveElement(elementID,final_x,final_y,interval)
    {
        if(!document.getElementById(elementID)) return false;
        var elem=document.getElementById(elementID);
      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+")";
        movement=setTimeout(repeat,interval);
    }
    function prepareSlideshow()
    {
        var preview=document.getElementById("preview");
        preview.style.position="absolute";
        preview.style.left="0px";
        preview.style.top="0px";
        // Get all the links in the list
        var list = document.getElementById("linklist");
        var links = list.getElementsByTagName("a");
        // Attach the animation behavior to the mouseover event
        links[0].onmouseover = function() {
        moveElement("preview",-100,0,10);
        }
        links[1].onmouseover = function() {
        moveElement("preview",-200,0,10);
        }
        links[2].onmouseover = function() {
        moveElement("preview",-300,0,10);
        }
      
    }
    
    window.onload=prepareSlideshow;
    </script>

    上面的代码有问题:

    something’s not quite right. If you move quickly from link to the link, the animation
    becomes confused. There’s something wrong with the moveElement function. 如果很快的在link移动,图片没有反应。

    A question of scope
    The animation problem is being caused by a global variable.
    When I abstracted the moveMessage function and turned it into the moveElement function,
    I left the variable movement as it was:

    var repeat ="moveElement('"+elementID+"',"+final_x+","+final_y+","+interval+")";
    movement = setTimeout(repeat,interval);全局变量

    (注意:

    function test()
    {
        str="sming";
    }
    test();
    alert(str);

    上面的 变量str我在函数内之间调用会被js当做是全局变量,会输出str的值)。

    This is causing a problem now that the moveElement function is being called whenever the
    user hovers over a link. Regardless of whether or not the previous call to the function has
    finished moving the image, the function is being asked to move the same element somewhere
    else. In other words, the moveElement function is attempting to move the same element
    to two different places at once and the movement variable has become the rope in a
    tug of war. As the user quickly moves from link to link, there is a backlog of events building
    up in the setTimeout queue.
    I can flush out this backlog(冲掉未完成的工作) by using clearTimeout:
    clearTimeout(movement);
    But if this statement is executed before movement has been set, I’ll get an error.

    I can’t use a local variable:
    var movement = setTimeout(repeat,interval);
    If I do that, then the clearTimeout statement won’t work; the movement variable will no
    longer exist.
    I can’t use a global variable. I can’t use a local variable. I need something in between. I
    need a variable that applies just to the element being moved.
    Element-specific variables do exist. In fact, you’ve been using them all the time. What I’ve
    just described is a property.
    Until now, you’ve used properties provided by the DOM:
    element.firstChild
    element.style
    etc.
    You can also assign your own properties:

    element.property = value

    If you wanted, you could create a property called foo with a value of “bar”:
    element.foo = "bar";
    It’s just like creating a variable. The difference is that the variable belongs just to that element.

    I’m going to change movement from being a global variable to a property of the element
    being moved, elem. That way, I can test for its existence and, if it exists, use clearTimeout

    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,interval);
    }

    Refining the animation
    The moveElement function moves an element one pixel at a time until it reaches the coordinates
    specified by the final_x and final_y arguments. The movement is smooth, but
    it’s also kind of boring.
    I’m going to spice up the animation a bit.
    Take a look at this simple bit of code in moveElement.js:
    if (xpos < final_x) {
    xpos++;
    }

    No matter how far away the element is from its final position, it will always move toward
    it one pixel at a time. I’m going to change that. If the element is far away from its final
    position, I want it to move a large distance. If the element is near to its final position, I
    want it to move a short distance.
    First of all, I need to figure out how far the element is from its final destination. If xpos is
    less than final_x, I want to know by how much. I can find out by subtracting xpos, the
    current left position, from final_x, the desired left position:

    var dist = final_x - xpos;

    That’s the distance that the element needs to travel. I’m going to move the element onetenth
    of this distance. I’ve chosen one-tenth as a nice round fraction. You can try other
    values if you like:
    var dist = (final_x - xpos)/10;
    xpos = xpos + dist;
    This will move the element one-tenth of the distance it needs to go.

    A problem occurs when the distance between xpos and final_x is less than 10. When that
    value is divided by 10, the result will be less than one. You can’t move an element by less
    than one pixel

    Math.floor(number)
    Math.round(number)

    Math.ceil(number)

    For the moveElement function, I’m going to round upward. If I used floor or round, the
    element might never reach its final destination:
    var dist = Math.ceil((final_x - xpos)/10);
    xpos = xpos + dist;
    This covers the situation when xpos is less than final_x:
    if (xpos < final_x) {
    var dist = Math.ceil((final_x - xpos)/10);
    xpos = xpos + dist;
    }

    <script>
    
    function test()
    {
        str="sming";
    }
    test();
    alert(str);
    
    function moveElement(elementID,final_x,final_y,interval)
    {
        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)
        {
            var dist = Math.ceil((final_x - xpos)/10);
            xpos = xpos + dist;
        }
        if(xpos>final_x)
        {
            var dist = Math.ceil((xpos - final_x)/10);
            xpos = xpos - dist;
        }
        if (ypos < final_y) 
        {
         var dist = Math.ceil((final_y - ypos)/10);
         ypos = ypos + dist;
        }
        if (ypos > final_y) 
        {
          var dist = Math.ceil((ypos - final_y)/10);
          ypos = ypos - dist;
        }
        elem.style.left=xpos+"px";
        elem.style.top=ypos+"px";
        var repeat="moveElement('"+elementID+"',"+final_x+","+final_y+","+interval+")";
        elem.movement=setTimeout(repeat,interval);
    }

    The animation now feels much smoother and snappier. When you first hover over a link,
    the image jumps quite a distance. As the image approaches its final destination, it “eases”
    into place.
    The markup, the CSS, and the JavaScript all come together to create this slideshow effect.
    Everything is working fine, but there’s always room for some small tweaks.

     final touches 最后的修饰

    The moveElement function is working really well now. There’s just one thing that bothers
    me. There is an assumption being made near the start of the function:
                      var xpos = parseInt(elem.style.left);
                     var ypos = parseInt(elem.style.top);
    I’m assuming that the element elem has a left style property and a top style property. I
    should really check to make sure that this is the case.
    If the left or top properties haven’t been set, I have a couple of options. I could simply
    exit the function there and then:
    if (!elem.style.left || !elem.style.top) {
    return false;
    }
    If JavaScript can’t read those properties, then the function stops without throwing up an
    error message.

     Another solution is to apply default left and top properties in the moveElement function.

    If either property hasn’t been set, I can give them a default value of “0px”:

    if (!elem.style.left) {
    elem.style.left = "0px";
    }
    if (!elem.style.top) {
    elem.style.top = "0px";
    }
  • 相关阅读:
    PAT1064(上)分析部分
    网络支付极其简单的体会
    L3,please send me a card
    PAT1008
    里氏转换
    数组遍历问题
    注册登录界面(简陋版)
    表单事件,onblur,onfocus,焦点
    复制所有链接,全选,反选
    剪切板
  • 原文地址:https://www.cnblogs.com/youxin/p/2660443.html
Copyright © 2020-2023  润新知