根據上圖實現除doAnimation
外的邏輯:javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jQuery之$().animate()的實現</title>
</head>
<body>
<script src="jQuery.js"></script>
<div id="A" style="width:100px;height:50px;background-color: deeppink">這是A</div>
<script>
//匿名函數自調用,下面好長好長的function就是$
//也就是說$是一個function(){xxx}
(function($) {
window.$ = $;
})(
//這裏也是匿名函數自調用
//本質就是通過一系列操做獲得chenQuery並做爲參數$,賦值給window.$
function() {
//匹配ID
let rquickExpr = /^(?:#([\w-]*))$/;
//jQuery初始化
function chenQuery(selector) {
return new chenQuery.fn.init(selector);
}
//假設是在數據緩存中存取隊列
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()
});
}
//每調用一次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'
});
};
</script>
</body>
</html>
複製代碼
解析:
(1)匿名函數自調用的參數:html
(function(a){
console.log(a) //name
})('name')
(function (b) {
console.log(b) //function(){console.log('name')}
})(function () {
console.log('name')
})
複製代碼
(2)快速匹配id選擇器java
//匹配ID
let rquickExpr = /^(?:#([\w-]*))$/;
複製代碼
(3)inprogress是動畫鎖
當第一個動畫執行時,向Queue
中添加鎖inprogress
,阻止異步調用動畫,也就是要求同步執行動畫,當動畫結束時,移除鎖,調用下一個動畫。web
(4)transitionendtransitionend
事件在 CSS 完成過渡後觸發,這裏當作單個動畫完成的信號,觸發後,會告知下個動畫進行算法
下圖的實現將在下篇文章貼出:緩存
(完)app