jQueryのシミュレーションは$().animate()(下)


前言:前編の基礎の上で、doAnimation()にアクセスします
論理図:
実装:



  
  jQuery $().animate()   




A
// (function(a){ // console.log(a) //name // })('name') // // (function (b) { // console.log(b) //function(){console.log('name')} // })(function () { // console.log('name') // }) // , function $ // $ function(){xxx} (function($) { window.$ = $; })( // // chenQuery $, window.$ function() { // ID let rquickExpr = /^(?:#([\w-]*))$/; //jQuery function chenQuery(selector) { return new chenQuery.fn.init(selector); } function getStyles(elem) { return elem.ownerDocument.defaultView.getComputedStyle(elem, null); } // swing // , function swing(p) { return 0.5 - Math.cos(p * Math.PI) / 2; } // // function Tween(value, prop, animation) { this.elem=animation.elem; this.prop=prop; this.easing= "swing"; // this.options=animation.options; // this.start=this.now = this.get(); // this.end= value; // this.unit="px" } Tween.prototype = { // get: function() { let computed = getStyles(this.elem); let ret = computed.getPropertyValue(this.prop) || computed[this.prop]; return parseFloat(ret); }, // run:function(percent){ let eased // percent this.pos = eased = swing(percent); // this.now = (this.end - this.start) * eased + this.start; // this.elem.style[this.prop] = this.now + "px"; return this; } } // function createFxNow() { setTimeout(function() { Animation.fxNow = undefined; }); return (Animation.fxNow = Date.now()); } let inProgress function schedule() { //inProgress // inProgress=null , if ( inProgress ) { // // requestAnimationFrame // window.requestAnimationFrame( schedule ); /* */ Animation.fx.tick(); } } // function Animation(elem, options, optall,func,){ // let animation = { elem:elem, props:options, originalOptions:optall, options:optall, // startTime:Animation.fxNow || createFxNow(), // , tweens:[] } // for (let k in options) { // tweens animation.tweens.push( new Tween(options[k], k, animation) ) } // let stopped; // // let tick = function() { if (stopped) { return false; } // let currentTime = Animation.fxNow || createFxNow, // remaining = Math.max(0, animation.startTime + animation.options.duration - currentTime), // temp = remaining / animation.options.duration || 0, percent = 1 - temp; let index = 0, length = animation.tweens.length; // for (; index < length; index++) { //percent animation.tweens[index].run(percent); } // 100% , if (percent < 1 && length) { return remaining; } // tick.complete() return false } tick.elem = elem; tick.anim = animation // , tick.complete = func // Animation.fx.timer(tick) } // requestAnimationFrame Animation.timers =[] Animation.fx = { // , //Animation.tick() timer: function(timer,) { Animation.timers.push(timer); if (timer()) { // Animation.fx.start(); // func() } // else { // Animation.timers.pop(); // } }, // start: function(func) { if ( inProgress ) { return; } // , inProgress = true; // schedule(); // func() }, // stop:function(){ inProgress = null; }, // tick: function() { var timer, i = 0, timers = Animation.timers; Animation.fxNow = Date.now(); for (; i < timers.length; i++) { timer = timers[i]; if (!timer() && timers[i] === timer) { // timers.splice(i--, 1); } } if (!timers.length) { Animation.fx.stop(); } Animation.fxNow = undefined; } } // const Queue=[] // const dataPriv={ get:function (type) { if(type==='queue') return Queue }, } const dequeue=function() { const Queue=dataPriv.get("queue") let fn = Queue.shift() // , const next = function() { dequeue(); } if ( fn === "inprogress" ) { fn = Queue.shift(); } if (fn) { Queue.unshift( "inprogress" ); /* doAnimation ,doAnimation(element, options,function() {firing = false;_fire();})*/ /*fn func*/ /*func , function*/ //func , const func=function() { next(); } fn(func); } } // type const queue=function(element, options, callback, ) { // , Queue.push const Queue=dataPriv.get("queue") // doAnimation Queue.push(function(func) { //doAnimation callback(element, options, func); }); // , // inprogress if(Queue[0]!=='inprogress'){ dequeue() } } /* */ const animation = function(element,options) { const doAnimation = function(element, options, func) { // const width = options.width /*=== , Animation ===*/ // 2s // element.style.transitionDuration = '400ms'; // element.style.width = width + 'px'; /* */ //transitionend CSS // element.addEventListener('transitionend', function() { // func() // }); // let optall={ complete:function(){}, old:false, duration: 400, easing: undefined, queue:"fx", } let anim=Animation(element, options, optall,func) } // animation, return queue(element, options,doAnimation,); } // chenQuery fn prototype animate chenQuery.fn = chenQuery.prototype = { // animation , , animate: function(options) { animation(this.element, options); // this, $("#A"), animate // return this; } } // chenQuery fn init const init = chenQuery.fn.init = function(selector) { // ["#A", "A",groups: undefined,index: 0,input: "#A"] const match = rquickExpr.exec(selector); // id const element = document.getElementById(match[1]) //this chenQuery.fn.init // element this.element = element; // chenQuery.fn.init return this; } // , init chenQuery.fn init.prototype = chenQuery.fn; //chenQuery function(){} // chenQuery{ //init fn,fn init // fn:{ // animate:function(){}, // init:function(){}, // // init.prototype=fn // }, // prototype:{ // animate:function(){}, // } // } return chenQuery; }()); const A = document.querySelector('#A'); // , // A.onclick = function() { // animation.add() $('#A').animate({ 'width': '500' }).animate({ 'width': '300' }).animate({ 'width': '1000' }); };

実行結果:
解析:(1)単一のアニメーション自体にもループがあり、つまりrequestAnimationFrameを利用してアニメーションフレームをループし、それによってアニメーションを描画する(2)percent <1の場合、すなわちアニメーションの実行時間が全体の時間より小さく、アニメーションフレームを絶えず実行する.percent =1の場合、アニメーションが終了したことを示し、アニメーションキューに通知し、次のアニメーションを実行し、ループすればよい
(完)