Dom元素变换效果(工具函数)
时间:2010-10-17 来源:岑安
做前端或者js程序员的同学应该都有感受,在日常工作中,用的最多的功能,一个是ajax与后台的数据接口,另一个就是对Dom元素的style控制,来达到不同的变换效果。用js来控制行为,控制页面表现。恐怕是我们用它来做的最多的事情了...
jQuery为什么这么受欢迎,我想,一方面是它的选择器[selector]足够牛B,另一方面应该要归功于它在dom变换上做足了功夫。
于是,秉承着一个宅男的宗旨,周末花了两个晚上稍微总结了一下,写了一段控制dom元素变换的代码,与目前强大的框架比起来,确实显得有点拙劣,不过作为日常开发的工具函数,我想还是蛮实用的。(这也是我最初的目的 ^_^)。
开门见山,先把源码完整的贴出来:(本着分享学习的原则,源代码你可以任意修改)
代码
//////////////* = Hongru.anim.js =*///////////
// @author: hongru.chen //
// @date: 2010-10-17 //
////////////////////////////////////////////
var Hongru = {
get : function (id) {return document.getElementById(id)},
tween : {
linear : function (f, t, d) { return t * d + f; },
ease : function (f, t, d) { return -t * .5 * (Math.cos(Math.PI * d) - 1) + f; }
},
tweens: [],
tweensCnt: 0,
anim : function (obj, params) {
var self = this,
objList = [],
objReturn = [];
var animimg = function () {
var i = -1, o;
while( o = self.tweens[++i] ) {
var cTime = (new Date()).getTime() - o.start;
if (cTime < o.duration) {
for (var k in o.val) {
var m = o.val[k];
o.obj[k] = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0);
}
} else {
cTime = o.duration;
for (var k in o.val) {
var m = o.val[k];
o.obj[k] = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0);
}
self.tweens.splice(i, 1);
self.tweensCnt--;
if (o.onFinish) o.onFinish (o.params);
self.stop();
}
if (!o.cssMode) o.obj.onTween();
}
};
if (typeof obj == "string" || !obj.length) objList.push(obj); else objList = obj;
for (var il = 0, l = objList.length; il < l; il++) {
var obj = this.get(objList[il]) || objList[il];
var o = {};
o.val = {};
o.cssMode = true;
o.o = obj;
o.obj = obj.style;
for (var k in params) {
var p = params[k];
if (k === "cssMode") {
if (p === false) {
o.cssMode = false;
o.obj = obj;
}
} else if (k === "onTween") {
o.obj.onTween = p;
} else if (k === "from") {
for (var i in p) o.obj[i] = o.cssMode ? (Math.ceil(p[i]) + 'px') : p[i];
} else if (k === "to") {
for (var i in p) {
var from = o.cssMode ? (parseInt(o.obj[i]) || 0) : (o.obj[i] || 0);
o.val[i] = {
from: from,
diff: p[i] - from
};
}
} else o[k] = params[k];
}
if (!o.ease) o.ease = this.tween.ease;
if (!o.cssMode && params['from']) o.obj.onTween();
o.duration = params.duration ? params.duration : 1000;
o.start = (new Date()).getTime();
this.tweens.push(o);
this.tweensCnt++;
if (!this.running) this.running = window.setInterval(animimg, 10);
objReturn.push(o);
}
return objReturn.length === 1 ? o : objReturn;
},
stop : function () {
if (!this.tweensCnt) {
window.clearInterval(this.running);
this.running = false;
}
},
kill : function (obj) {
if (obj) {
for (var i = 0; i < this.tweensCnt; i++) {
if (this.tweens[i] === obj || this.tweens[i].o === obj || this.tweens[i].o === this.get(obj)) {
this.tweensCnt--;
this.tweens.splice(i, 1);
this.stop();
}
}
}
},
reset : function () {
this.tweensCnt = 0;
this.stop();
while( this.tweens.length ) {
this.tweens.stop();
}
}
}
从调用方式来看,其实我的实现方法有点类似于YUI,以下是个最简单的例子:
Hongru.anim(id, {
from: {
top: 0,
left: 100
},
to: {
left: 500,
}
});
以下是调用这段代码的效果:
<!Doctype html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <title>Tweens demo</title> <script type="text/javascript">//////////////* = Hongru.anim.js =*/////////// // @author: hongru.chen // // @date: 2010-10-17 // //////////////////////////////////////////// var Hongru = { get : function (id) {return document.getElementById(id)}, tween : { linear : function (f, t, d) { return t * d + f; }, ease : function (f, t, d) { return -t * .5 * (Math.cos(Math.PI * d) - 1) + f; } }, tweens: [], tweensCnt: 0, anim : function (obj, params) { var self = this, objList = [], objReturn = []; var animimg = function () { var i = -1, o; while( o = self.tweens[++i] ) { var cTime = (new Date()).getTime() - o.start; if (cTime < o.duration) { for (var k in o.val) { var m = o.val[k]; o.obj[k] = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0); } } else { cTime = o.duration; for (var k in o.val) { var m = o.val[k]; o.obj[k] = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0); } self.tweens.splice(i, 1); self.tweensCnt--; if (o.onFinish) o.onFinish (o.params); self.stop(); } if (!o.cssMode) o.obj.onTween(); } }; if (typeof obj == "string" || !obj.length) objList.push(obj); else objList = obj; for (var il = 0, l = objList.length; il < l; il++) { var obj = this.get(objList[il]) || objList[il]; var o = {}; o.val = {}; o.cssMode = true; o.o = obj; o.obj = obj.style; for (var k in params) { var p = params[k]; if (k === "cssMode") { if (p === false) { o.cssMode = false; o.obj = obj; } } else if (k === "onTween") { o.obj.onTween = p; } else if (k === "from") { for (var i in p) o.obj[i] = o.cssMode ? (Math.ceil(p[i]) + 'px') : p[i]; } else if (k === "to") { for (var i in p) { var from = o.cssMode ? (parseInt(o.obj[i]) || 0) : (o.obj[i] || 0); o.val[i] = { from: from, diff: p[i] - from }; } } else o[k] = params[k]; } if (!o.ease) o.ease = this.tween.ease; if (!o.cssMode && params['from']) o.obj.onTween(); o.duration = params.duration ? params.duration : 1000; o.start = (new Date()).getTime(); this.tweens.push(o); this.tweensCnt++; if (!this.running) this.running = window.setInterval(animimg, 10); objReturn.push(o); } return objReturn.length === 1 ? o : objReturn; }, stop : function () { if (!this.tweensCnt) { window.clearInterval(this.running); this.running = false; } }, kill : function (obj) { if (obj) { for (var i = 0; i < this.tweensCnt; i++) { if (this.tweens[i] === obj || this.tweens[i].o === obj || this.tweens[i].o === this.get(obj)) { this.tweensCnt--; this.tweens.splice(i, 1); this.stop(); } } } }, reset : function () { this.tweensCnt = 0; this.stop(); while( this.tweens.length ) { this.tweens.stop(); } } }</script> <style type="text/css" _mce_bogus="1"><!-- .container{border:4px solid #ccc;position:relative;margin-bottom:10px} ul,li{margin:0;padding:0} --></style> </head> <body> <script type="text/javascript"><!-- function tween1 (id) { //此id参数可以是obj,也可以是字符串id,还可以是数组['id1','id2','id3'] Hongru.anim(id, { from: { top: 0, left: 100 }, to: { left: 500, } }); } // --></script> <div class="container" style=""> <button onclick='tween1("test1")'>Animate!</button><br /> <div id="test1" style="border:4px solid #333;width:50px;position:absolute" _mce_style="border: 4px solid #333; width: 50px; position: absolute;"></div> </div> </body> </html>
当然,这是最简单的方式,此外,我在参数id上,花了点小心思,anim()的第一个参数不仅可以是我们常见的字符串"id",也可以是HtmlObject,比如同样是上面的代码:
function tween1 (id) { //此id参数可以是obj,也可以是字符串id,还可以是数组['id1','id2','id3']
Hongru.anim(id, {
from: {
top: 0,
left: 100
},
to: {
left: 500,
}
});
}
可以对一个元素这样来调用
onclick="tween1(this)"
this直接指向元素本身,演示如下。
<!Doctype html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <title>Tweens demo</title> <script type="text/javascript">//////////////* = Hongru.anim.js =*/////////// // @author: hongru.chen // // @date: 2010-10-17 // //////////////////////////////////////////// var Hongru = { get : function (id) {return document.getElementById(id)}, tween : { linear : function (f, t, d) { return t * d + f; }, ease : function (f, t, d) { return -t * .5 * (Math.cos(Math.PI * d) - 1) + f; } }, tweens: [], tweensCnt: 0, anim : function (obj, params) { var self = this, objList = [], objReturn = []; var animimg = function () { var i = -1, o; while( o = self.tweens[++i] ) { var cTime = (new Date()).getTime() - o.start; if (cTime < o.duration) { for (var k in o.val) { var m = o.val[k]; o.obj[k] = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0); } } else { cTime = o.duration; for (var k in o.val) { var m = o.val[k]; o.obj[k] = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0); } self.tweens.splice(i, 1); self.tweensCnt--; if (o.onFinish) o.onFinish (o.params); self.stop(); } if (!o.cssMode) o.obj.onTween(); } }; if (typeof obj == "string" || !obj.length) objList.push(obj); else objList = obj; for (var il = 0, l = objList.length; il < l; il++) { var obj = this.get(objList[il]) || objList[il]; var o = {}; o.val = {}; o.cssMode = true; o.o = obj; o.obj = obj.style; for (var k in params) { var p = params[k]; if (k === "cssMode") { if (p === false) { o.cssMode = false; o.obj = obj; } } else if (k === "onTween") { o.obj.onTween = p; } else if (k === "from") { for (var i in p) o.obj[i] = o.cssMode ? (Math.ceil(p[i]) + 'px') : p[i]; } else if (k === "to") { for (var i in p) { var from = o.cssMode ? (parseInt(o.obj[i]) || 0) : (o.obj[i] || 0); o.val[i] = { from: from, diff: p[i] - from }; } } else o[k] = params[k]; } if (!o.ease) o.ease = this.tween.ease; if (!o.cssMode && params['from']) o.obj.onTween(); o.duration = params.duration ? params.duration : 1000; o.start = (new Date()).getTime(); this.tweens.push(o); this.tweensCnt++; if (!this.running) this.running = window.setInterval(animimg, 10); objReturn.push(o); } return objReturn.length === 1 ? o : objReturn; }, stop : function () { if (!this.tweensCnt) { window.clearInterval(this.running); this.running = false; } }, kill : function (obj) { if (obj) { for (var i = 0; i < this.tweensCnt; i++) { if (this.tweens[i] === obj || this.tweens[i].o === obj || this.tweens[i].o === this.get(obj)) { this.tweensCnt--; this.tweens.splice(i, 1); this.stop(); } } } }, reset : function () { this.tweensCnt = 0; this.stop(); while( this.tweens.length ) { this.tweens.stop(); } } }</script> <style type="text/css" _mce_bogus="1"><!-- .container{border:4px solid #ccc;position:relative;margin-bottom:10px} ul,li{margin:0;padding:0} --></style> </head> <body> <script type="text/javascript"><!-- function tween1 (id) { //此id参数可以是obj,也可以是字符串id,还可以是数组['id1','id2','id3'] Hongru.anim(id, { from: { top: 0, left: 100 }, to: { left: 500, } }); } // --></script> <div class="container" style=""> <div style="border:4px solid blue;width:50px;position:absolute;margin-top:120px;cursor:pointer;" _mce_style="border: 4px solid blue; width: 50px; position: absolute; margin-top: 120px; cursor: pointer;" onclick="tween1(this)">click me!</div></div> </div> </body> </html>
另外,还可以控制多个元素同时变换,也就是说,id可以是个数组如['id1', 'id2', 'id3'].演示如下:
<!Doctype html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <title>Tweens demo</title> <script type="text/javascript">//////////////* = Hongru.anim.js =*/////////// // @author: hongru.chen // // @date: 2010-10-17 // //////////////////////////////////////////// var Hongru = { get : function (id) {return document.getElementById(id)}, tween : { linear : function (f, t, d) { return t * d + f; }, ease : function (f, t, d) { return -t * .5 * (Math.cos(Math.PI * d) - 1) + f; } }, tweens: [], tweensCnt: 0, anim : function (obj, params) { var self = this, objList = [], objReturn = []; var animimg = function () { var i = -1, o; while( o = self.tweens[++i] ) { var cTime = (new Date()).getTime() - o.start; if (cTime < o.duration) { for (var k in o.val) { var m = o.val[k]; o.obj[k] = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0); } } else { cTime = o.duration; for (var k in o.val) { var m = o.val[k]; o.obj[k] = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0); } self.tweens.splice(i, 1); self.tweensCnt--; if (o.onFinish) o.onFinish (o.params); self.stop(); } if (!o.cssMode) o.obj.onTween(); } }; if (typeof obj == "string" || !obj.length) objList.push(obj); else objList = obj; for (var il = 0, l = objList.length; il < l; il++) { var obj = this.get(objList[il]) || objList[il]; var o = {}; o.val = {}; o.cssMode = true; o.o = obj; o.obj = obj.style; for (var k in params) { var p = params[k]; if (k === "cssMode") { if (p === false) { o.cssMode = false; o.obj = obj; } } else if (k === "onTween") { o.obj.onTween = p; } else if (k === "from") { for (var i in p) o.obj[i] = o.cssMode ? (Math.ceil(p[i]) + 'px') : p[i]; } else if (k === "to") { for (var i in p) { var from = o.cssMode ? (parseInt(o.obj[i]) || 0) : (o.obj[i] || 0); o.val[i] = { from: from, diff: p[i] - from }; } } else o[k] = params[k]; } if (!o.ease) o.ease = this.tween.ease; if (!o.cssMode && params['from']) o.obj.onTween(); o.duration = params.duration ? params.duration : 1000; o.start = (new Date()).getTime(); this.tweens.push(o); this.tweensCnt++; if (!this.running) this.running = window.setInterval(animimg, 10); objReturn.push(o); } return objReturn.length === 1 ? o : objReturn; }, stop : function () { if (!this.tweensCnt) { window.clearInterval(this.running); this.running = false; } }, kill : function (obj) { if (obj) { for (var i = 0; i < this.tweensCnt; i++) { if (this.tweens[i] === obj || this.tweens[i].o === obj || this.tweens[i].o === this.get(obj)) { this.tweensCnt--; this.tweens.splice(i, 1); this.stop(); } } } }, reset : function () { this.tweensCnt = 0; this.stop(); while( this.tweens.length ) { this.tweens.stop(); } } }</script> <style type="text/css" _mce_bogus="1"><!-- .container{border:4px solid #ccc;position:relative;margin-bottom:10px} ul,li{margin:0;padding:0} --></style> </head> <body> <script type="text/javascript"><!-- function tween1 (id) { //此id参数可以是obj,也可以是字符串id,还可以是数组['id1','id2','id3'] Hongru.anim(id, { from: { top: 0, left: 100 }, to: { left: 500, } }); } // --></script> <div class="container" style=""> <button onclick='tween1("test1")'>Animate!</button><br /> <button onclick='tween1(["test1","test2"])'>Animate all!</button> <div id="test1" style="border:4px solid #333;width:50px;position:absolute" _mce_style="border: 4px solid #333; width: 50px; position: absolute;"></div> <div id="test2" style="border:4px solid red;width:50px;position:absolute;margin-top:60px" _mce_style="border: 4px solid red; width: 50px; position: absolute; margin-top: 60px;"></div> </div> </div> </body> </html>
以上可以支持object和数组selector的功能,暂可以称为【功能一】,
【功能二】
支持回调函数callback,也就是可以实现咱们常说的chain-animate,链式变换。具体是通过onFinish参数来实现的。核心源码很简单,就是在一个变换完毕之后判断有没有onFinish,如果有就调用:
代码var animimg = function () {
var i = -1, o;
while( o = self.tweens[++i] ) {
var cTime = (new Date()).getTime() - o.start;
if (cTime < o.duration) {
for (var k in o.val) {
var m = o.val[k];
o.obj[k] = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0);
}
} else {
cTime = o.duration;
for (var k in o.val) {
var m = o.val[k];
o.obj[k] = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0);
}
self.tweens.splice(i, 1);
self.tweensCnt--;
if (o.onFinish) o.onFinish (o.params);
self.stop();
}
if (!o.cssMode) o.obj.onTween();
}
};
下面是通过递归调用实现chain-animate的一个演示:
<!Doctype html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <title>Tweens demo</title> <script type="text/javascript">//////////////* = Hongru.anim.js =*/////////// // @author: hongru.chen // // @date: 2010-10-17 // //////////////////////////////////////////// var Hongru = { get : function (id) {return document.getElementById(id)}, tween : { linear : function (f, t, d) { return t * d + f; }, ease : function (f, t, d) { return -t * .5 * (Math.cos(Math.PI * d) - 1) + f; } }, tweens: [], tweensCnt: 0, anim : function (obj, params) { var self = this, objList = [], objReturn = []; var animimg = function () { var i = -1, o; while( o = self.tweens[++i] ) { var cTime = (new Date()).getTime() - o.start; if (cTime < o.duration) { for (var k in o.val) { var m = o.val[k]; o.obj[k] = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0); } } else { cTime = o.duration; for (var k in o.val) { var m = o.val[k]; o.obj[k] = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0); } self.tweens.splice(i, 1); self.tweensCnt--; if (o.onFinish) o.onFinish (o.params); self.stop(); } if (!o.cssMode) o.obj.onTween(); } }; if (typeof obj == "string" || !obj.length) objList.push(obj); else objList = obj; for (var il = 0, l = objList.length; il < l; il++) { var obj = this.get(objList[il]) || objList[il]; var o = {}; o.val = {}; o.cssMode = true; o.o = obj; o.obj = obj.style; for (var k in params) { var p = params[k]; if (k === "cssMode") { if (p === false) { o.cssMode = false; o.obj = obj; } } else if (k === "onTween") { o.obj.onTween = p; } else if (k === "from") { for (var i in p) o.obj[i] = o.cssMode ? (Math.ceil(p[i]) + 'px') : p[i]; } else if (k === "to") { for (var i in p) { var from = o.cssMode ? (parseInt(o.obj[i]) || 0) : (o.obj[i] || 0); o.val[i] = { from: from, diff: p[i] - from }; } } else o[k] = params[k]; } if (!o.ease) o.ease = this.tween.ease; if (!o.cssMode && params['from']) o.obj.onTween(); o.duration = params.duration ? params.duration : 1000; o.start = (new Date()).getTime(); this.tweens.push(o); this.tweensCnt++; if (!this.running) this.running = window.setInterval(animimg, 10); objReturn.push(o); } return objReturn.length === 1 ? o : objReturn; }, stop : function () { if (!this.tweensCnt) { window.clearInterval(this.running); this.running = false; } }, kill : function (obj) { if (obj) { for (var i = 0; i < this.tweensCnt; i++) { if (this.tweens[i] === obj || this.tweens[i].o === obj || this.tweens[i].o === this.get(obj)) { this.tweensCnt--; this.tweens.splice(i, 1); this.stop(); } } } }, reset : function () { this.tweensCnt = 0; this.stop(); while( this.tweens.length ) { this.tweens.stop(); } } }</script> <style type="text/css" _mce_bogus="1"><!-- .container{border:4px solid #ccc;position:relative;margin-bottom:10px} ul,li{margin:0;padding:0} --></style> </head> <body> <script type="text/javascript"><!-- /*===========*/ function tween2 (id) { //Hongru.running = true / false //Hongru.kill(id) to stop and kill running Hongru of a given HTML element //Hongru.reset() to stop the whole engine Hongru.kill(id); Hongru.anim(id, { from: { top: 0, left: 0, width: 106, } }); } // --></script> <div class="container"> <button onclick='if(!Hongru.running)tween2("test3")'>Animate!</button> <button onclick='Hongru.kill("test3")'>Stop</button><br /> <div id="test3" style="border:4px solid green;width:50px;position:absolute;margin-left:200px" _mce_style="border: 4px solid green; width: 50px; position: absolute; margin-left: 200px;"></div> </div> </body> </html>
到这里,相信以前做过类似工作的同学们都觉得这还不够,毕竟如果只实现所有和‘盒模型’沾边的属性的变换应该都不算难事。比如高宽,padding,margin,left,top等等这些可以用像素做单位的属性。他们的变换都可以统一起来。但是如果要实现颜色变换,透明度变换呢,恐怕就不是我的短短几十百来行代码就可以做到的。
是的,我承认,要把颜色,透明度等等所有属性变换都封装起来,需要做的判断就不是一点两点了。所以呢,在这里,我也没有对“盒模型”以外的属性变换做封装。但并不代表没有想到他们的实现方法。
既然写死在代码里要费事,那就我们自己调用的时候多写两句代码不就好了吗,毕竟代码是死的,人是活的。我这里做了个cssMode的参数判断(思路是借鉴一个老外的)。代码成本很低。如果不是可以用px做单位的属性,我们可以自己控制它的样式变换。比如实现背景色变换:
function test3 (id) {
Hongru.anim(id, {
cssMode: false, // animation will be handled by an external function
onTween : function () {
// custom function, can be as simple or as complex as needed
this.style.background = "RGB("+this.r+","+this.g+","this.b")";
},
from : { r: 0, g: 0, b: 0 },
to: { r: 255, g: 128, b: 100 }
});
}
把cssMode设置为false之后,会执行onTween里的代码,这样就可以自行控制样式的变换了,如上。演示如下:
<!Doctype html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <title>Tweens demo</title> <script type="text/javascript">//////////////* = Hongru.anim.js =*/////////// // @author: hongru.chen // // @date: 2010-10-17 // //////////////////////////////////////////// var Hongru = { get : function (id) {return document.getElementById(id)}, tween : { linear : function (f, t, d) { return t * d + f; }, ease : function (f, t, d) { return -t * .5 * (Math.cos(Math.PI * d) - 1) + f; } }, tweens: [], tweensCnt: 0, anim : function (obj, params) { var self = this, objList = [], objReturn = []; var animimg = function () { var i = -1, o; while( o = self.tweens[++i] ) { var cTime = (new Date()).getTime() - o.start; if (cTime < o.duration) { for (var k in o.val) { var m = o.val[k]; o.obj[k] = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0); } } else { cTime = o.duration; for (var k in o.val) { var m = o.val[k]; o.obj[k] = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0); } self.tweens.splice(i, 1); self.tweensCnt--; if (o.onFinish) o.onFinish (o.params); self.stop(); } if (!o.cssMode) o.obj.onTween(); } }; if (typeof obj == "string" || !obj.length) objList.push(obj); else objList = obj; for (var il = 0, l = objList.length; il < l; il++) { var obj = this.get(objList[il]) || objList[il]; var o = {}; o.val = {}; o.cssMode = true; o.o = obj; o.obj = obj.style; for (var k in params) { var p = params[k]; if (k === "cssMode") { if (p === false) { o.cssMode = false; o.obj = obj; } } else if (k === "onTween") { o.obj.onTween = p; } else if (k === "from") { for (var i in p) o.obj[i] = o.cssMode ? (Math.ceil(p[i]) + 'px') : p[i]; } else if (k === "to") { for (var i in p) { var from = o.cssMode ? (parseInt(o.obj[i]) || 0) : (o.obj[i] || 0); o.val[i] = { from: from, diff: p[i] - from }; } } else o[k] = params[k]; } if (!o.ease) o.ease = this.tween.ease; if (!o.cssMode && params['from']) o.obj.onTween(); o.duration = params.duration ? params.duration : 1000; o.start = (new Date()).getTime(); this.tweens.push(o); this.tweensCnt++; if (!this.running) this.running = window.setInterval(animimg, 10); objReturn.push(o); } return objReturn.length === 1 ? o : objReturn; }, stop : function () { if (!this.tweensCnt) { window.clearInterval(this.running); this.running = false; } }, kill : function (obj) { if (obj) { for (var i = 0; i < this.tweensCnt; i++) { if (this.tweens[i] === obj || this.tweens[i].o === obj || this.tweens[i].o === this.get(obj)) { this.tweensCnt--; this.tweens.splice(i, 1); this.stop(); } } } }, reset : function () { this.tweensCnt = 0; this.stop(); while( this.tweens.length ) { this.tweens.stop(); } } }</script> <style type="text/css" _mce_bogus="1"><!-- .container{border:4px solid #ccc;position:relative;margin-bottom:10px} ul,li{margin:0;padding:0} --></style> </head> <body> <script type="text/javascript"><!-- function test3 (id) { Hongru.anim(id, { cssMode: false, // animation will be handled by an external function onTween : function () { // custom function, can be as simple or as complex as needed this.style.background = 'RGB('+this.r+','+this.g+','+this.b+')'; }, from : { r: 0, g: 0, b: 0 }, to: { r: 111, g: 222, b: 50 } }); } // --></script> <div class="container"> <button onclick="test3('o-anim')">Animate!</button> <div id="o-anim" style="border:4px solid green;background:red;width:200px;position:absolute;margin-left:200px" _mce_style="border: 4px solid green; background: red; width: 200px; position: absolute; margin-left: 200px;"></div> </div> </body> </html>
同样,透明度也可以自行设置,
<!Doctype html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <title>Tweens demo</title> <script type="text/javascript">//////////////* = Hongru.anim.js =*/////////// // @author: hongru.chen // // @date: 2010-10-17 // //////////////////////////////////////////// var Hongru = { get : function (id) {return document.getElementById(id)}, tween : { linear : function (f, t, d) { return t * d + f; }, ease : function (f, t, d) { return -t * .5 * (Math.cos(Math.PI * d) - 1) + f; } }, tweens: [], tweensCnt: 0, anim : function (obj, params) { var self = this, objList = [], objReturn = []; var animimg = function () { var i = -1, o; while( o = self.tweens[++i] ) { var cTime = (new Date()).getTime() - o.start; if (cTime < o.duration) { for (var k in o.val) { var m = o.val[k]; o.obj[k] = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0); } } else { cTime = o.duration; for (var k in o.val) { var m = o.val[k]; o.obj[k] = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0); } self.tweens.splice(i, 1); self.tweensCnt--; if (o.onFinish) o.onFinish (o.params); self.stop(); } if (!o.cssMode) o.obj.onTween(); } }; if (typeof obj == "string" || !obj.length) objList.push(obj); else objList = obj; for (var il = 0, l = objList.length; il < l; il++) { var obj = this.get(objList[il]) || objList[il]; var o = {}; o.val = {}; o.cssMode = true; o.o = obj; o.obj = obj.style; for (var k in params) { var p = params[k]; if (k === "cssMode") { if (p === false) { o.cssMode = false; o.obj = obj; } } else if (k === "onTween") { o.obj.onTween = p; } else if (k === "from") { for (var i in p) o.obj[i] = o.cssMode ? (Math.ceil(p[i]) + 'px') : p[i]; } else if (k === "to") { for (var i in p) { var from = o.cssMode ? (parseInt(o.obj[i]) || 0) : (o.obj[i] || 0); o.val[i] = { from: from, diff: p[i] - from }; } } else o[k] = params[k]; } if (!o.ease) o.ease = this.tween.ease; if (!o.cssMode && params['from']) o.obj.onTween(); o.duration = params.duration ? params.duration : 1000; o.start = (new Date()).getTime(); this.tweens.push(o); this.tweensCnt++; if (!this.running) this.running = window.setInterval(animimg, 10); objReturn.push(o); } return objReturn.length === 1 ? o : objReturn; }, stop : function () { if (!this.tweensCnt) { window.clearInterval(this.running); this.running = false; } }, kill : function (obj) { if (obj) { for (var i = 0; i < this.tweensCnt; i++) { if (this.tweens[i] === obj || this.tweens[i].o === obj || this.tweens[i].o === this.get(obj)) { this.tweensCnt--; this.tweens.splice(i, 1); this.stop(); } } } }, reset : function () { this.tweensCnt = 0; this.stop(); while( this.tweens.length ) { this.tweens.stop(); } } }</script> <style type="text/css" _mce_bogus="1"><!-- .container{border:4px solid #ccc;position:relative;margin-bottom:10px} ul,li{margin:0;padding:0} --></style> </head> <body> <script type="text/javascript"><!-- function test3 (id) { Hongru.anim(id, { cssMode: false, // animation will be handled by an external function onTween : function () { // custom function, can be as simple or as complex as needed this.style.opacity = this.o/100; this.style.filter = 'alpha(opacity='+this.o+')'; }, from : { o: 100 }, to: { o: 0 } }); } // --></script> <div class="container"> <button onclick="test3('o-anim')">Animate!</button> <div id="o-anim" style="border:4px solid green;background:red;width:200px;position:absolute;margin-left:200px" _mce_style="border: 4px solid green; background: red; width: 200px; position: absolute; margin-left: 200px;"></div> </div> </body> </html>
好了,鉴于篇幅和时间,此文基本都在介绍功能,对代码没怎么细讲,有兴趣的同学可以自己看看,反正源码也贴出来了,而且原理都不难。
另外,在这个函数使用中,Hongru.kill(id)是停止指定对象的变换。Hongru.reset()是停止所有正在变换的效果。至于Hongru本身,大家可以随意更改。
时间不早了,洗洗睡吧