在學(xué)習(xí)javascript動(dòng)畫效果的過程,動(dòng)畫函數(shù)一定是少不了的,所以在初級學(xué)習(xí)的過程中钞护,封裝好一個(gè)動(dòng)畫函數(shù)可以直接調(diào)用能夠幫我們省下更多的學(xué)習(xí)時(shí)間喉祭。下面是我一步步完善動(dòng)畫函數(shù)的過程养渴。
1、簡單的右移函數(shù):鼠標(biāo)點(diǎn)擊按鈕泛烙,box向右移動(dòng)一定的位置
//封裝右移動(dòng)畫函數(shù)
function animateMoveRight(element,target){
//通過offsetLeft獲取當(dāng)前位置的left值
var left = element.offsetLeft;
//開啟定時(shí)器
var timer = setInterval(function(){
//當(dāng)前位置每一次+5 實(shí)現(xiàn)勻速運(yùn)動(dòng)
left += 5;
//將每一次改變后的left值設(shè)置給元素
element.style.left = left + 'px';
//判斷動(dòng)畫結(jié)束的標(biāo)志 到達(dá)目標(biāo)位置停止計(jì)時(shí)器
if(left >= target){
clearInterval(timer);
}
},30);
}
//在window.onload中調(diào)用封裝好的動(dòng)畫函數(shù)
window.onload =function () {
var box = document.getElementById('box');
//動(dòng)態(tài)創(chuàng)建按鈕
for(var i = 200; i < 1000; i += 100){
//創(chuàng)建按鈕
var button = document.createElement('button');
button.innerHTML = '右移' + i + 'px';
//獲取按鈕對應(yīng)的移動(dòng)值
button.index = i;
//點(diǎn)擊按鈕
button.onclick = function(){
// console.log(this.index);
//調(diào)用封裝好的右移函數(shù)
animateMoveRight(box,this.index);
}
//添加按鈕
document.body.appendChild(button);
}
}
</script>
實(shí)現(xiàn)效果:
2理卑、封裝同時(shí)解決左右移動(dòng)的動(dòng)畫函數(shù)
上面的函數(shù)只能實(shí)現(xiàn)單向的向右移動(dòng),點(diǎn)擊‘右移500px’按鈕后蔽氨,再點(diǎn)擊‘右移200px’按鈕無法回到200px處藐唠。下面實(shí)現(xiàn)這種效果。
//封裝一個(gè)函數(shù) 同時(shí)解決左右移動(dòng)的問題
function animateMove(element,target){
clearInterval(timer)
var left = element.offsetLeft;
//設(shè)置步長 表示一步動(dòng)作的差值
//通過比較element當(dāng)前的left值和target值的大小鹉究,來確定平移方向
var step = (target - left) / 10;
var timer = setInterval(function(){
//如果目標(biāo)值大于當(dāng)前的left值宇立,step為正數(shù),向右移動(dòng)
//如果目標(biāo)值小于當(dāng)前的left值自赔,step為負(fù)數(shù)妈嘹,向左移動(dòng)
left += step;
box.style.left = left + 'px';
//判斷停止動(dòng)畫
//比較差值,取絕對值绍妨,當(dāng)兩者的差值小于了步進(jìn)值時(shí)润脸,停止動(dòng)畫,
if(Math.abs(target - left) <= Math.abs(step)){
clearInterval(timer);
element.style.left = target + 'px';
}
},30);
}
//調(diào)用函數(shù)
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);
}
}
效果展示:(當(dāng)前在400px位置他去,點(diǎn)擊200px按鈕會(huì)回到200px位置)
3津函、封裝帶有指定屬性的動(dòng)畫函數(shù)
在設(shè)置動(dòng)畫的過程中,不只是左右移動(dòng)那么簡單孤页,我們想要是的是想改變元素的什么屬性就能夠改變尔苦。在開始之前先了解怎么訪問并獲取css的屬性。
3.1 訪問css屬性
我們知道element.style.xxx 只能夠獲取行內(nèi)式屬性,無法獲取在style中設(shè)置的屬性允坚;offset獲取的是本身實(shí)際獲得的魂那,沒有定位,沒有設(shè)left夜里可以獲得稠项。我們通過設(shè)置element.currentStyle.xxx(ie瀏覽器)或者window.getComputedStyle(element, null).xxx(其他瀏覽器)獲得涯雅。封裝函數(shù)如下:
1 //封裝一個(gè)函數(shù),用于獲取某一個(gè)元素的某一條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 封裝帶有指定屬性的動(dòng)畫函數(shù)
//引入getStyle函數(shù)
function getStyle(element, styleName){
if(element.currentStyle){
return element.currentStyle[styleName];
}else{
var computedStyle = window.getComputedStyle(element, null);
return computedStyle[styleName];
}
}
//封裝帶有指定屬性的的動(dòng)畫函數(shù) (元素名,屬性名展运,目標(biāo)值)
var timer;
function animate(element,styleName,target){
clearInterval(timer);
//獲取該元素當(dāng)前的屬性
var current = parseInt(getStyle(element,styleName));
//設(shè)置步長 定值
var step = (target - current) / 10;
//開啟動(dòng)畫設(shè)置滾動(dòng)效果移動(dòng)
timer = setInterval(function(){
//通過步長 一點(diǎn)的的改變current 直到達(dá)到target值
current += step;
//判斷動(dòng)畫結(jié)束的標(biāo)志
//比較差值 當(dāng)兩者的差值小于了步進(jìn)值時(shí)活逆,停止動(dòng)畫
if(Math.abs(target - current) <= Math.abs(step)){
clearInterval(element.timer);
current = target; //存在一點(diǎn)誤差 強(qiáng)制將current歸為目標(biāo)值
}
//將改變后當(dāng)前動(dòng)畫中的style值,設(shè)置給動(dòng)畫的元素
element.style[styleName] = current + 'px';
},30);
}
//調(diào)用
window.onload = function(){
var box =document.getElementById('box');
animate(box,'width',500);
}
4拗胜、封裝帶有多個(gè)屬性的動(dòng)畫函數(shù)(同時(shí)運(yùn)動(dòng))
前面雖然能根據(jù)傳入的屬性參數(shù)改變元素運(yùn)動(dòng)蔗候,但是每次只能設(shè)置一種屬性,如果同時(shí)調(diào)用只會(huì)顯示最后一種效果埂软。所以下面使用json參數(shù)傳入多個(gè)屬性锈遥。
<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>
//獲取屬性的的網(wǎng)頁中實(shí)際的(當(dāng)前的)屬性值
function getStyle(element, styleName){
if(element.currentStyle){
return element.currentStyle[styleName];
}else{
var computedStyle = window.getComputedStyle(element, null);
return computedStyle[styleName];
}
}
//封裝帶有多個(gè)屬性的的動(dòng)畫函數(shù) 利用json參數(shù)
function animate(element,json){
clearInterval(element.timer);
//由于多個(gè)屬性的運(yùn)動(dòng) 為了避免一個(gè)屬性完成后就停止定時(shí)器的現(xiàn)象,所以設(shè)置isStop
//是否停止動(dòng)畫,默認(rèn)為false表示不停止
var isStop = false;
//開啟動(dòng)畫設(shè)置滾動(dòng)效果移動(dòng)
element.timer = setInterval(function(){
//1.每一次動(dòng)畫開啟之前,默認(rèn)設(shè)置isStop為true(定時(shí)器停止)
//2.如果只是一個(gè)屬性完成不需要修改定時(shí)器,如果有屬性沒有 執(zhí)行完,則設(shè)置isStop = false,繼續(xù)開啟定時(shí)器
//3.最后所有屬性都完成后, 判斷isStop值 如果為true,表示的屬性均執(zhí)行完成,關(guān)閉定時(shí)器
//1.
isStop = true;
//多個(gè)屬性 分別計(jì)算每個(gè)屬性當(dāng)前值(實(shí)際值)/目標(biāo)值/步長
//遍歷json參數(shù) 分別獲取key-屬性名 json[key]-屬性值
for(var key in json){
console.log(key); //left top
console.log(json[key]); // 100 50
//通過getStyle函數(shù)獲取當(dāng)前屬性(key)的屬性值即盒子的當(dāng)前實(shí)際值
var current = parseInt(getStyle(element, key));
//獲取json參數(shù)傳入的每個(gè)屬性對應(yīng)的目標(biāo)值
var target = json[key];
//分別設(shè)置每個(gè)屬性步長
var step = (target - current) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
//設(shè)置一步步的改變 直至達(dá)到目標(biāo)值
current += step;
//判斷(current += step)是否達(dá)到目標(biāo)值 停止計(jì)時(shí)器
//2.其中一個(gè)屬性完成,就不需要修改定時(shí)器
if(Math.abs(target -current) > Math.abs(step)){
isStop = false;
}else{ //強(qiáng)制將此屬性設(shè)到target
current = target;
}
//設(shè)置運(yùn)動(dòng)后的值給元素, 改變其對應(yīng)屬性的屬性值
element.style[key] = current + 'px';
}
//3.所有的屬性動(dòng)畫完成(for(key)結(jié)束),所有的定時(shí)器都為true,關(guān)閉定時(shí)器
if(isStop){
clearInterval(element.timer);
console.log('完成動(dòng)畫');
}
},30);
}
//調(diào)用此函數(shù)
window.onload = function(){
var box =document.getElementById('box');
document.onclick =function(){
//實(shí)現(xiàn)點(diǎn)擊后勘畔,在一定時(shí)間內(nèi)同時(shí)完成以下動(dòng)作
animate(box,{
left:200,
top :200,
width:300,
height:300
});
}
}
實(shí)現(xiàn)效果:鼠標(biāo)點(diǎn)擊后所灸,在一定時(shí)間內(nèi)盒子同時(shí)向左向下移動(dòng)200px,并且寬高擴(kuò)大到300px炫七。
5爬立、函數(shù)的回歸調(diào)用(上一個(gè)動(dòng)畫運(yùn)動(dòng)完成后下一個(gè)動(dòng)畫才開始運(yùn)動(dòng))
上面的代碼實(shí)現(xiàn)了一個(gè)物體的多個(gè)屬性同時(shí)運(yùn)動(dòng),很多情況下會(huì)是一個(gè)物體的上一個(gè)動(dòng)畫完成后另一個(gè)動(dòng)畫才開始運(yùn)動(dòng)万哪。所以我們在原來的基礎(chǔ)上傳入一個(gè)函數(shù)參數(shù)侠驯,function animate(element,json,fun){},在上一個(gè)動(dòng)畫完成后壤圃,開始調(diào)用下一個(gè)動(dòng)畫的函數(shù)參數(shù)陵霉。
//回調(diào)函數(shù)
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{ //強(qiáng)制將此屬性設(shè)到target
current = target;
}
element.style[key] = current + 'px';
}
if(isStop){
clearInterval(element.timer);
console.log('完成動(dòng)畫');
console.log(element.offsetLeft);
//上一個(gè)動(dòng)畫完成后琅轧,開始下一個(gè)動(dòng)畫
if(typeof fun == 'function'){
fun();
}
}
},30);
}
window.onload = function(){
var box =document.getElementById('box');
document.onclick =function(){
//先向右移動(dòng)到500px,接著寬高均擴(kuò)大到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);
});
});
});
}
}
實(shí)現(xiàn)效果:鼠標(biāo)點(diǎn)擊后伍绳,盒子先向右移動(dòng)到500px,接著寬高均擴(kuò)大到300px,下移到150px,字體放大到30px。
6乍桂、封裝帶有opacity冲杀、z-index等屬性的動(dòng)畫函數(shù)
//思路:即查看current,target,step的值是否會(huì)因?yàn)閛pacity的傳入而出錯(cuò)
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,取浮點(diǎn)型數(shù)
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;
//判斷暫停動(dòng)畫
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{ //強(qiáng)制將此屬性設(shè)到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('完成動(dòng)畫');
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);
}
}
實(shí)現(xiàn)效果:透明度由1 變?yōu)?.3 睹酌,z-index由10 變?yōu)?0权谁。
到這里一個(gè)較為完善的動(dòng)畫函數(shù)就封裝完成了。
如有任何疑問請留言憋沿。
接下將介紹幾種通過js動(dòng)畫效果實(shí)現(xiàn)各式輪播圖的案例......