页面动画是一种很常见的效果,很多同学因它而对js产生兴趣,甚至jquery把它放在核心库里。
QWrap的核心库,并没有提供动画组件。wagang版动画组件是依赖QWrap开发出的一个动画组件。它的前身是youa网站使用的animation组件,原作者是Jerry Qu,改装成wagang组件时作了一些修改。
文档与示例参见:http://dev.qwrap.com/resource/js/wagang/anim/_examples/index.html
anim.js是一个复合js,它由四个js组成:

document.write('<script type="text/javascript" src="' + srcPath + 'wagang/anim/anim_base.js"></script>');
document.write(
'<script type="text/javascript" src="' + srcPath + 'wagang/anim/elanim.js"></script>');
document.write(
'<script type="text/javascript" src="' + srcPath + 'wagang/anim/easing.js"></script>');
document.write(
'<script type="text/javascript" src="' + srcPath + 'wagang/anim/anim_retouch.js"></script>');

动画提供了以下四个类:
anim_base.js产出基础动画类QW.Anim。主要是时间、帧、播放进度等的一个管理器,相当于一个万能动画。
elanim.js产出三个针对元素的动画类:QW.ElAnim、QW.ColorAnim、QW.ScrollAnim 。
easing.js产出算子集合:QW.Easing。
anim_retouch.js是添加一些易于调用的动画相关方法,例如:W('#id').toggleSlide();

先看一下基础动画类。源码大略为:
View Code
/*
Copyright QWrap
version: $version$ $release$ released
author: JK
*/

(
function() {
var CustEvent = QW.CustEvent,
mix
= QW.ObjectH.mix;

/**
* @class Anim 动画
* @namespace QW
* @constructor
* @param {function} animFun - 管理动画效果的闭包
* @param {int} dur - 动画效果持续的时间
* @param {json} opts - 其它参数,
---目前只支持以下参数:
{boolean} byStep (Optional) 是否按帧动画(即"不跳帧")。如果为true,表示每一帧都走到,帧数为dur/frameTime
{boolean} frameTime (Optional) 帧间隔时间。默认为28
{boolean} per (Optional) 初始播放进度
{function} onbeforeplay (Optional) onbeforeplay事件
{function} onplay (Optional) onplay事件
{function} onstep (Optional) onstep事件
{function} onpause (Optional) onpause事件
{function} onresume (Optional) onresume事件
{function} onstop (Optional) onstop事件
{function} onsuspend (Optional) onsuspend事件
{function} onreset (Optional) onreset事件
* @returns {Anim} anim - 动画对象
*/
var Anim = function(animFun, dur, opts) {
mix(
this, opts);
mix(
this, {
animFun: animFun,
//animFun,动画函数,
dur: dur, //动画时长
byStep: false, //是否按帧动画
per: 0, //播放进度
frameTime: 28, //帧间隔时间
_status: 0 //0-未播放,1-播放中,2-播放结束,4-被暂停,8-被终止
});
changePer(
this, this.per);
CustEvent.createEvents(
this, Anim.EVENTS);
};

Anim.EVENTS
= 'beforeplay,play,step,pause,resume,stop,suspend,reset'.split(',');
/*
* turnOn 打开动画定时器
* @param {Anim} anim Anim实例
* @returns {void}
*/

function turnOn(anim) {
anim.step();
if (anim.isPlaying()) {
anim._interval
= window.setInterval(function() {
anim.step();
}, anim.frameTime);
}
}
/*
* turnOff 关闭动画定时器
* @param {Anim} anim Anim实例
* @returns {void}
*/

function turnOff(anim) {
window.clearInterval(anim._interval);
}
/*
* changePer 调整播放进度,进度值
* @param {Anim} anim Anim实例
* @param {number} per 进度值,为[0,1]区间内的数值
* @returns {void}
*/

function changePer(anim, per) {
anim.per
= per;
anim._startDate
= new Date() * 1 - per * anim.dur;
if (anim.byStep) {
anim._totalStep
= anim.dur / anim.frameTime;
anim._currentStep
= per * anim._totalStep;
}
}

mix(Anim.prototype, {
/**
* 判断是否正在播放
* @method isPlaying
* @returns {boolean}
*/
isPlaying:
function() {
return this._status == 1;
},
/**
* 从0开始播放
* @method play
* @returns {boolean} 是否开始顺利开始。(因为onbeforeplay有可能阻止了play)
*/
play:
function() {
var me = this;
if (me.isPlaying()) me.stop();
changePer(me,
0);
if (!me.fire('beforeplay')) return false;
me._status
= 1;
me.fire(
'play');
turnOn(me);
return true;
},
/**
* 播放一帧
* @method step
* @param {number} per (Optional) 进度值,为[0,1]区间内的数值
* @returns {void}
*/
step:
function(per) {
var me = this;
if (per != null) {
changePer(me, per);
}
else {
if (me.byStep) {
per
= me._currentStep++ / me._totalStep;
}
else {
per
= (new Date() - me._startDate) / me.dur;
}
this.per = per;
}
if (this.per > 1) {
this.per = 1;
}
me.animFun(
this.per);
me.fire(
'step');
if (this.per >= 1) {
this.suspend();
return;
}
},
/**
* 停止播放,并预归位到0。
* @method stop
* @returns {void}
*/
stop:
function() {
this._status = 8;
changePer(
this, 0);
turnOff(
this);
this.fire('stop');
},
/**
* 播放到最后
* @method suspend
* @returns {void}
*/
suspend:
function() {
changePer(
this, 1);
this.animFun(1);
this._status = 2;
turnOff(
this);
this.fire('suspend');
},
/**
* 暂停播放
* @method pause
* @returns {void}
*/
pause:
function() {
this._status = 4;
turnOff(
this);
this.fire('pause');
},
/**
* 继续播放
* @method resume
* @returns {void}
*/
resume:
function() {
changePer(
this, this.per);
this._status = 1;
this.fire('resume');
turnOn(
this);
},
/**
* 播放到最开始
* @method reset
* @returns {void}
*/
reset:
function() {
changePer(
this, 0);
this.animFun(0);
this.fire('reset');
}
});
QW.provide(
'Anim', Anim);
}());


我们把动画抽象一下,它由以下几个组成部分:
    时长(dur),即动画播放的时间总长。
    进度(per),播放的进度,在区间[0,1]之内。
    帧间隔时间(frameTime),即多长时间播放一帧。
    动画函数(animFun),它是每一帧的渲染函数。定时器每隔frameTime来调用一下animFun(per)。也就是说按进度播放一帧动画。
这四个基本参数将动画抽象成为一个js类,系统的理解就是:
在dur时间内,每隔frameTime时间,播放一次animFun(per)。

这个类实例可以有以下方法:
    isPlaying() 判断是否正在播放 -----returns {boolean} 
    play() 从0开始播放 ----returns {boolean} 是否开始顺利开始。(因为onbeforeplay有可能阻止了play)
    step(per) 播放一帧,参数per为[0,1]区间内的数值,为可选,表示播放到某进度
    stop() 停止播放,并预归位到0。
    suspend() 播放到最后
    pause() 暂停播放
    resume() 继续播放
    reset() 播放到最开始

“在dur时间内,每隔frameTime时间,播放一次animFun(per)。”
例如:一个“在3秒时间内,每0.1秒,播放function(per){document.getElementById('div1').style.height = (per * 100) +'px';}”
对应的效果就是:在3秒时间内,将div1元素的高度从0变成100。
代码如下:
View Code
<HTML>
<HEAD>
<META content="text/html; charset=gb2312" http-equiv=Content-Type>
<TITLE>JK Test</TITLE>
<script src="http://dev.qwrap.com/resource/js/apps/core_dom_youa.combo.js"></script>
<script src="http://dev.qwrap.com/resource/js/wagang/anim/anim_base.js"></script>
<style>
#div1
{background-color:#ccc;overflow:hidden;height:100px;}
</style>
</HEAD>
<body>
<div id="div1" onclick="test();">点我</div>
</body>
<script type="text/javascript">
function test(){
var anim=new QW.Anim(
function(per){
document.getElementById(
'div1').style.height=(100*per)+'px';
},
3000,
{frameTime:
100}
);
anim.play();
}
</script>
</HTML>

待续。。。。

附:QWrap网址:http://www.qwrap.com

作者: JKisJK 发表于 2011-06-06 17:58 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"