在前面的隨筆中介紹了如何用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>
代碼中的那張圖片是:

上面這段代碼實現的特效的是:當鼠標放到超鏈接上,就能以動畫的效果顯示對應的字母。
效果很酷,但是代碼存在一點小瑕疵,這點我們經常容易忽視,問題就是,當我們把鼠標指針在鏈接之間快速的來回移動,動畫效果將變得混亂起來。
