在前面的随笔中介绍了如何用DOM技术修改文档的央样式信息,用JavaScript添加样式信息可以节约我们的时间和精力,但总的来说,CSS仍是完成这类任务的最佳工具。但是有一个应用领域是目前的CSS无能为力的。如果我们想随着时间的变化而不断改变某个元素的样式,则只能用JavaScript。JavaScript能够按照预定的时间间隔重复的调用一个函数,而意味着我们可以随着时间的推移而不断改变某个元素的样式。
动画是样式随着时间变化的完美例子之一。简单的说,动画就是让元素的位置随着时间而不断的发生变化。下面来说下使用JavaScript动画,必须要掌握的几个HTML的基本知识:
一、位置
网页元素在浏览器窗口中的位置是一种表示性的信息。因此,位置信息通常使用CSS负责设置的。下面这段CSS代码对某个元素在网页上的位置做了预定:
element{ position:absolute; top:50px; left:100px; }
position属性的合法值有static、absolute、relative、fixed四种。
1、static是position属性的默认值,意思是有关元素将按照它们在标记里出现的先后顺序出现在浏览器窗口里。
2、relative的含义与static相似,区别是postion属性为relative的元素还可以(通过应用float属性)从文档的正常显示顺序中脱离出来。
3、如果一个元素的position属性设为absolute时,我们就可以把它摆到容纳它的"容器"的任何位置。这个容器要么是文档本身,要么是一个有着fixed或absolute属性的父元素。他的显示位置由top、left、right、bottom四个属性决定和他本身在文档中的位置无关。
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> <style type="text/css"> </style> </head> <body> <p id="message">Whee!</p><!--(使兴奋,使激动,啊)!--> <script type="text/javascript"> //通过js来设置<p>标签的初试显示位置 function positionMessage() { if (!checkCompatibility) return; var ele = document.getElementById("message"); ele.style.position = "absolute"; ele.style.top = "100px"; ele.style.left = "50px"; } //通过style属性改变<p>标签的显示位置 function moveMessage() { var ele = document.getElementById("message"); ele.style.left = "200px"; } var loadeventlist = [positionMessage, moveMessage]; addOnloadEventlist(loadeventlist); //给window.onload事件绑定函数数组 这个函数数组将在页面全部加在完毕之后被调用 function addOnloadEventlist(eventlist) { if (!eventlist) return false; var oldonload = window.onload; window.onload = function () { for (var i = 0; i < eventlist.length; i++) { eventlist[i](); } } } //检查浏览器对DOM方法的支持 function checkCompatibility() { if (!document.getElementById) return false; if (!document.createElement) return false; if (!document.createTextNode) return false; if (!document.getElementsByTagName) return false; if (!document.getElementsByName) return false; return true; } </script> </body> </html>
上面这段代码,我们看不到任何动画效果,因为我们的JavaScript太有效率了;函数一个接一个的执行.期间根本没有我们能察觉的间隔。
所以为了实现动画效果,我们必须创造出时间间隔来,而这正是实现动画效果的关键!所以我们来说下时间动画效果的第二个要素时间!
二、时间
1、setTimeut()函数 他能够让某个函数在经过一段预定的时间之后才开始执行。这个函数有两个参数:第一个参数是一个字符串,其内容是将要执行的那个函数的名字。第二个参数是一个数值,他以毫秒为单位设定了需要经过多长时间才开始执行第一个参数所给出的函数。
setTimeout("functionExample",interval) //interval时间间隔 是一个数值
但是这样写名称为functionExample的函数,将会一直被调用而不会停止,所以正确的代码应该这样写,除非你是打算让他一直被调用!
var para=setTimeout(" ",interval);
这样将把对functionExample函数的调用赋值给para变量,这样如果我们想取消正在排队等待执行的函数,就可以这样做
clearTimeout(para);
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> </head> <body> <p id="message">Whee!</p><!--(使兴奋,使激动,啊)!--> <script type="text/javascript"> //通过js来设置<p>标签的初试显示位置 function positionMessage() { if (!checkCompatibility) return; var ele = document.getElementById("message"); ele.style.position = "absolute"; ele.style.top = "50px"; ele.style.left = "50px"; } //通过style属性改变<p>标签的显示位置 function moveMessage() { var ele = document.getElementById("message"); var xpos = parseInt(ele.style.left); var ypos = parseInt(ele.style.top); if (xpos == 200 && ypos == 100) { return true; } if (xpos < 100) { xpos++; } if (xpos > 100) { xpos--; } if (ypos > 100) { ypos--; } if (ypos < 100) { ypos++; } ele.style.left = xpos + "px"; ele.style.top = ypos + "px"; movement=setTimeout("moveMessage()", 6); } var loadeventlist = [positionMessage, moveMessage]; addOnloadEventlist(loadeventlist); //给window.onload事件绑定函数数组 这个函数数组将在页面全部加在完毕之后被调用 function addOnloadEventlist(eventlist) { if (!eventlist) return false; var oldonload = window.onload; window.onload = function () { for (var i = 0; i < eventlist.length; i++) { eventlist[i](); } } } //检查浏览器对DOM方法的支持 function checkCompatibility() { if (!document.getElementById) return false; if (!document.createElement) return false; if (!document.createTextNode) return false; if (!document.getElementsByTagName) return false; if (!document.getElementsByName) return false; return true; } </script> </body> </html>
上面这段代码完美的实现了我们想要实现的动画效果,通过每次移动一点位置和setTimeout()函数配合,实现了这个效果,代码观察代码发现上面这段代码还可以优化,让它变得更加的通用!因为所有这些信息都是硬编码在函数代码里。元素只能移动到固定的位置,而且两次移动之间的时间也是固定的!如果把这些常量都改为变量,这个函数的通用性和灵活性将会大大增加。下面的代码将会对上面这段代码进行抽象!
下面是分析上面那个函数后总结出新函数可能变化的东西,然后把它作为变量,交给使用者赋值,增加函数的通用性和灵活性
1、打算移动的元素ID
2、元素移动终点的横坐标
3、元素移动终点的纵坐标
4、每次元素移动所产生的时间间隔
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> </head> <body> <p id="message"> Whee!</p> <!--(使兴奋,使激动,啊)!--> <script type="text/javascript"> //通过js来设置<p>标签的初试显示位置 function positionMessage() { if (!checkCompatibility) return; var ele = document.getElementById("message"); ele.style.position = "absolute"; ele.style.top = "100px"; ele.style.left = "50px"; moveElement("message",200,100,5); } function moveElement(elementID, final_x, final_y, interval) { //下面是每次调用这个新函数可能变化的东西 //1、打算移动的元素ID -elementID //2、元素移动终点的横坐标 -final_x //3、元素移动终点的纵坐标 -final_y //4、每次元素移动所产生的时间间隔 interval //为上面的变化的东西取个描述性的名字便于理解 if (!document.getElementById(elementID)) { return false; } else { var ele = document.getElementById(elementID); } var xpos = parseInt(ele.style.left); var ypos = parseInt(ele.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++; } ele.style.left = xpos + "px"; ele.style.top = ypos + "px"; var repeat = "moveElement('" + elementID + "','" + final_x + "','" + final_y + "','" + interval + "')"; movement = setTimeout(repeat, interval); } var loadeventlist = [positionMessage]; addOnloadEventlist(loadeventlist); //给window.onload事件绑定函数数组 这个函数数组将在页面全部加在完毕之后被调用 function addOnloadEventlist(eventlist) { if (!eventlist) return false; var oldonload = window.onload; window.onload = function () { for (var i = 0; i < eventlist.length; i++) { eventlist[i](); } } } //检查浏览器对DOM方法的支持 function checkCompatibility() { if (!document.getElementById) return false; if (!document.createElement) return false; if (!document.createTextNode) return false; if (!document.getElementsByTagName) return false; if (!document.getElementsByName) return false; return true; } </script> </body> </html>
这段代码相比与上面那段代码,代码的灵活度和通用度,明显提高了!
下面我们就用封装好的moveElement函数做一个常用的网页特效demo
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <style type="text/css"> #slideshow { width:100px; height:100px; position:relative; overflow:hidden; } </style> </head> <body> <h1> Web Design</h1> <p> These are things you should know</p> <ol id="linklist"> <li><a href="#">Structure</a></li> <li><a href="#">Presentation</a></li> <li><a href="#">Behavior</a></li> </ol> <div id="slideshow"> <img id="preview" alt=" " src="../img/topic.png" /> </div> <script type="text/javascript"> function prepareSlideshow() { if (!checkCompatibility()) return false; if (!document.getElementById("linklist")) return false; if (!document.getElementById("slideshow")) return false; var preview = document.getElementById("preview"); //获取预览图片的div preview.style.position = "absolute"; preview.style.left = "0px"; preview.style.top = "0px"; var list = document.getElementById("linklist"); var links = list.getElementsByTagName("a"); 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); } } function moveElement(elementID, final_x, final_y, interval) { //下面是每次调用这个新函数可能变化的东西 //1、打算移动的元素ID -elementID //2、元素移动终点的横坐标 -final_x //3、元素移动终点的纵坐标 -final_y //4、每次元素移动所产生的时间间隔 interval //为上面的变化的东西取个描述性的名字便于理解 if (!document.getElementById(elementID)) { return false; } else { var ele = document.getElementById(elementID); } var xpos = parseInt(ele.style.left); var ypos = parseInt(ele.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++; } ele.style.left = xpos + "px"; ele.style.top = ypos + "px"; var repeat = "moveElement('" + elementID + "','" + final_x + "','" + final_y + "','" + interval + "')"; movement = setTimeout(repeat, interval); } function checkCompatibility() { if (!document.getElementById) return false; if (!document.createElement) return false; if (!document.createTextNode) return false; if (!document.getElementsByTagName) return false; if (!document.getElementsByName) return false; return true; } function addOnloadEvent(func) { var oldonload = window.onload; if (typeof window.onload != "function") { window.onload = func; //如果window.onload事件没有绑定任何function则正常绑定 } else { //如果window.onload事件已经绑定了函数,则在原来的基础上,继续添加新的函数 window.onload = function () { oldonload(); func(); }; } } addOnloadEvent(prepareSlideshow); </script> </body> </html>
代码中的那张图片是:
上面这段代码实现的特效的是:当鼠标放到超链接上,就能以动画的效果显示对应的字母。
效果很酷,但是代码存在一点小瑕疵,这点我们经常容易忽视,问题就是,当我们把鼠标指针在链接之间快速的来回移动,动画效果将变得混乱起来。