在學習javascript動畫效果的過程,動畫函數一定是少不了的,所以在初級學習的過程中,封裝好一個動畫函數可以直接調用能夠幫我們省下更多的學習時間。下面是我一步步完善動畫函數的過程。
1、簡單的右移函數:鼠標點擊按鈕,box向右移動一定的位置
//封裝右移動畫函數
function animateMoveRight(element,target){
//通過offsetLeft獲取當前位置的left值
var left = element.offsetLeft;
//開啟定時器
var timer = setInterval(function(){
//當前位置每一次+5 實現勻速運動
left += 5;
//將每一次改變后的left值設置給元素
element.style.left = left + 'px';
//判斷動畫結束的標志 到達目標位置停止計時器
if(left >= target){
clearInterval(timer);
}
},30);
}
//在window.onload中調用封裝好的動畫函數
window.onload =function () {
var box = document.getElementById('box');
//動態創建按鈕
for(var i = 200; i < 1000; i += 100){
//創建按鈕
var button = document.createElement('button');
button.innerHTML = '右移' + i + 'px';
//獲取按鈕對應的移動值
button.index = i;
//點擊按鈕
button.onclick = function(){
// console.log(this.index);
//調用封裝好的右移函數
animateMoveRight(box,this.index);
}
//添加按鈕
document.body.appendChild(button);
}
}
</script>
實現效果:
2、封裝同時解決左右移動的動畫函數
上面的函數只能實現單向的向右移動,點擊‘右移500px’按鈕后,再點擊‘右移200px’按鈕無法回到200px處。下面實現這種效果。
//封裝一個函數 同時解決左右移動的問題
function animateMove(element,target){
clearInterval(timer)
var left = element.offsetLeft;
//設置步長 表示一步動作的差值
//通過比較element當前的left值和target值的大小,來確定平移方向
var step = (target - left) / 10;
var timer = setInterval(function(){
//如果目標值大于當前的left值,step為正數,向右移動
//如果目標值小于當前的left值,step為負數,向左移動
left += step;
box.style.left = left + 'px';
//判斷停止動畫
//比較差值,取絕對值,當兩者的差值小于了步進值時,停止動畫,
if(Math.abs(target - left) <= Math.abs(step)){
clearInterval(timer);
element.style.left = target + 'px';
}
},30);
}
//調用函數
window.onload =function () {
var box = document.getElementById('box');
for(var i = 200; i < 1000; i += 100){
var button = document.createElement('button');
button.innerHTML = '右移' + i + 'px';
button.target = i;
button.onclick = function(){
animateMove(box,this.target);
}
document.body.appendChild(button);
}
}
效果展示:(當前在400px位置,點擊200px按鈕會回到200px位置)
3、封裝帶有指定屬性的動畫函數
在設置動畫的過程中,不只是左右移動那么簡單,我們想要是的是想改變元素的什么屬性就能夠改變。在開始之前先了解怎么訪問并獲取css的屬性。
3.1 訪問css屬性
我們知道element.style.xxx 只能夠獲取行內式屬性,無法獲取在style中設置的屬性;offset獲取的是本身實際獲得的,沒有定位,沒有設left夜里可以獲得。我們通過設置element.currentStyle.xxx(ie瀏覽器)或者window.getComputedStyle(element, null).xxx(其他瀏覽器)獲得。封裝函數如下:
1 //封裝一個函數,用于獲取某一個元素的某一條CSS屬性值
2 function getStyle(element, styleName){
3 if(element.currentStyle){
4 return element.currentStyle[styleName];
5 }else{
6 var computedStyle = window.getComputedStyle(element, null);
7 return computedStyle[styleName];
8 }
9 }
10
11 window.onload = function(){
12 var box = document.getElementById('box');
13 var height = getStyle(box,'height');
14 console.log(height); //200px
15 }
3.2 封裝帶有指定屬性的動畫函數
//引入getStyle函數
function getStyle(element, styleName){
if(element.currentStyle){
return element.currentStyle[styleName];
}else{
var computedStyle = window.getComputedStyle(element, null);
return computedStyle[styleName];
}
}
//封裝帶有指定屬性的的動畫函數 (元素名,屬性名,目標值)
var timer;
function animate(element,styleName,target){
clearInterval(timer);
//獲取該元素當前的屬性
var current = parseInt(getStyle(element,styleName));
//設置步長 定值
var step = (target - current) / 10;
//開啟動畫設置滾動效果移動
timer = setInterval(function(){
//通過步長 一點的的改變current 直到達到target值
current += step;
//判斷動畫結束的標志
//比較差值 當兩者的差值小于了步進值時,停止動畫
if(Math.abs(target - current) <= Math.abs(step)){
clearInterval(element.timer);
current = target; //存在一點誤差 強制將current歸為目標值
}
//將改變后當前動畫中的style值,設置給動畫的元素
element.style[styleName] = current + 'px';
},30);
}
//調用
window.onload = function(){
var box =document.getElementById('box');
animate(box,'width',500);
}
4、封裝帶有多個屬性的動畫函數(同時運動)
前面雖然能根據傳入的屬性參數改變元素運動,但是每次只能設置一種屬性,如果同時調用只會顯示最后一種效果。所以下面使用json參數傳入多個屬性。
<script type="text/javascript">
//json格式參考
function f(){
var json ={left:100,top:50}
for(var key in json){
console.log(key); //打印屬性 left top
console.log(json[key]); //打印屬性值 100 50
}
}
f();
</script>
//獲取屬性的的網頁中實際的(當前的)屬性值
function getStyle(element, styleName){
if(element.currentStyle){
return element.currentStyle[styleName];
}else{
var computedStyle = window.getComputedStyle(element, null);
return computedStyle[styleName];
}
}
//封裝帶有多個屬性的的動畫函數 利用json參數
function animate(element,json){
clearInterval(element.timer);
//由于多個屬性的運動 為了避免一個屬性完成后就停止定時器的現象,所以設置isStop
//是否停止動畫,默認為false表示不停止
var isStop = false;
//開啟動畫設置滾動效果移動
element.timer = setInterval(function(){
//1.每一次動畫開啟之前,默認設置isStop為true(定時器停止)
//2.如果只是一個屬性完成不需要修改定時器,如果有屬性沒有 執行完,則設置isStop = false,繼續開啟定時器
//3.最后所有屬性都完成后, 判斷isStop值 如果為true,表示的屬性均執行完成,關閉定時器
//1.
isStop = true;
//多個屬性 分別計算每個屬性當前值(實際值)/目標值/步長
//遍歷json參數 分別獲取key-屬性名 json[key]-屬性值
for(var key in json){
console.log(key); //left top
console.log(json[key]); // 100 50
//通過getStyle函數獲取當前屬性(key)的屬性值即盒子的當前實際值
var current = parseInt(getStyle(element, key));
//獲取json參數傳入的每個屬性對應的目標值
var target = json[key];
//分別設置每個屬性步長
var step = (target - current) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
//設置一步步的改變 直至達到目標值
current += step;
//判斷(current += step)是否達到目標值 停止計時器
//2.其中一個屬性完成,就不需要修改定時器
if(Math.abs(target -current) > Math.abs(step)){
isStop = false;
}else{ //強制將此屬性設到target
current = target;
}
//設置運動后的值給元素, 改變其對應屬性的屬性值
element.style[key] = current + 'px';
}
//3.所有的屬性動畫完成(for(key)結束),所有的定時器都為true,關閉定時器
if(isStop){
clearInterval(element.timer);
console.log('完成動畫');
}
},30);
}
//調用此函數
window.onload = function(){
var box =document.getElementById('box');
document.onclick =function(){
//實現點擊后,在一定時間內同時完成以下動作
animate(box,{
left:200,
top :200,
width:300,
height:300
});
}
}
實現效果:鼠標點擊后,在一定時間內盒子同時向左向下移動200px,并且寬高擴大到300px。
5、函數的回歸調用(上一個動畫運動完成后下一個動畫才開始運動)
上面的代碼實現了一個物體的多個屬性同時運動,很多情況下會是一個物體的上一個動畫完成后另一個動畫才開始運動。所以我們在原來的基礎上傳入一個函數參數,function animate(element,json,fun){},在上一個動畫完成后,開始調用下一個動畫的函數參數。
//回調函數
function animate(element,json,fun){
clearInterval(element.timer);
console.log(element.offsetLeft + 'kaishiqian')
var isStop = false;
element.timer = setInterval(function(){
isStop = true;
for(var key in json){
console.log(key); //left top
console.log(json[key]); // 100 50
var current = parseInt(getStyle(element, key));
var target = json[key];
var step = (target - current) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
current += step;
if(Math.abs(target -current) > Math.abs(step)){
isStop = false;
}else{ //強制將此屬性設到target
current = target;
}
element.style[key] = current + 'px';
}
if(isStop){
clearInterval(element.timer);
console.log('完成動畫');
console.log(element.offsetLeft);
//上一個動畫完成后,開始下一個動畫
if(typeof fun == 'function'){
fun();
}
}
},30);
}
window.onload = function(){
var box =document.getElementById('box');
document.onclick =function(){
//先向右移動到500px,接著寬高均擴大到300px,下移到150px,字體放大到30px
animate(box,{left:500}, function(){
animate(box,{width:300, height:300}, function(){
animate(box,{top:150}, function(){
animate(box,{fontSize:30}, null);
});
});
});
}
}
實現效果:鼠標點擊后,盒子先向右移動到500px,接著寬高均擴大到300px,下移到150px,字體放大到30px。
6、封裝帶有opacity、z-index等屬性的動畫函數
//思路:即查看current,target,step的值是否會因為opacity的傳入而出錯
function animate(element,json,fun){
clearInterval(element.timer);
console.log(element.offsetLeft + 'kaishiqian')
var isStop = false;
element.timer = setInterval(function(){
isStop = true;
for(var key in json){
var current;
//如果傳入的屬性是opacity,取浮點型數
if(key == 'opacity'){
current = parseFloat(getStyle(element, key));
}else{
current = parseInt(getStyle(element, key));
}
//沒問題
var target = json[key];
//只要不是opacity 都做向上或向下取整操作
var step = (target - current) / 10;
if(key != 'opacity'){
step = step > 0 ? Math.ceil(step) : Math.floor(step);
}
current += step;
//判斷暫停動畫
if(key == 'opacity'){
if(Math.abs(target -current) > 0.01){
isStop = false;
}else{
current = target;
}
element.style[key] = current + '';
}else{
if(Math.abs(target -current) > Math.abs(step)){
isStop = false;
}else{ //強制將此屬性設到target
current = target;
}
if(key == 'zIndex'){
//四舍五入
element.style.zIndex = Math.round(current);
}else{
element.style[key] = current + 'px';
}
}
}
if(isStop){
clearInterval(element.timer);
console.log('完成動畫');
if(typeof fun == 'function'){
fun();
}
}
},30);
}
window.onload = function(){
var box =document.getElementById('box');
document.onclick =function(){
animate(box, {opacity:0.3,zIndex:20}, null);
}
}
實現效果:透明度由1 變為0.3 ,z-index由10 變為20。
到這里一個較為完善的動畫函數就封裝完成了。
如有任何疑問請留言。
接下將介紹幾種通過js動畫效果實現各式輪播圖的案例......