ホームページ  >  記事  >  ウェブフロントエンド  >  jQuery_javascript スキルと同じくらい使いやすい API スタイル コードを共有する

jQuery_javascript スキルと同じくらい使いやすい API スタイル コードを共有する

WBOY
WBOYオリジナル
2016-05-16 18:11:171383ブラウズ

本題に戻りますが、jQuery と同じくらい使いやすい API スタイルはありますか?それで、それはどのようなスタイルですか?私が個人的により重要だと思う点が 2 つあります。1 つは DOM 操作への呼び出しの連鎖です。これにより、コードのセマンティクスが理解しやすくなるだけでなく、複数の操作が不要になります。同じ DOM 要素を呼び出す場合、チェーン操作中にコールバックをコールバックに埋め込むことが非常に重要です。
2 番目は要素のバッチ操作で、強力なセレクターに基づいています。誰もが知っているように、jq セレクターは非常に強力なので、これ以上は言いません。そしてそれは確かに 1 日や 2 日で達成できるものではありません。そこで、先ほど述べた 2 つの点について私の考えを話しましょう。

その強力なセレクターに基づいて、すべての jquery DOM 操作は、そのセレクターに基づいて取得された配列に依存します。多くの人は、これを jq オブジェクトと呼びます。だから今はそう呼んでおこう。すべての DOM 操作は、この jq オブジェクト内の各要素に依存して、同時にバッチで実行されます。各 DOM 操作に特有の、それらのほとんどは連鎖コールバックの状態にあります。つまり、このメソッド チェーンでは、その実行順序は、チェーン内のメソッド呼び出しの順序に基づいて直接知ることができます。このメソッドチェーンとシリアル形式が大きな特徴です。
非常に多くの人が jquery を使用するのは、基本的に 2 つの理由からです。セレクターが非常に強力であること、チェーン コールが非常に便利で使いやすいこと、そしてコード ロジックが即座にシンプルになることです。多くのコード ロジックを内部で処理するため、プログラマーが考慮すべき問題が少なくなりますが、一方で、コーディング ロジックを練習する機会も失われます。したがって、初心者が jquery や他のフレームワークの使い方を直接学ぶことはお勧めしません。js の理解がますます薄れてしまうからです。私の考えは、すべてのフレームワークやライブラリは開発効率や管理の利便性を高めるために使われており、学習するために使われているわけではありません。 (もちろん、ソースコードを勉強する人は除きます)。
それでは、jquery の API スタイルは使いやすいと思うので、これと同様の API スタイルを構築してみませんか? (免責事項: 以下の試みはアイデアを提供することだけを目的としており、コードは完璧ではありません...)


var get = function (ids) {
var d = document, a = -1;
this.elements = []
if (typeof) ids != ' string' && !!ids.length) {
for (var i=0; ivar id = ids[i],
o; = typeof id = = 'string' ? d.getElementById(id) : id;
this.elements.push(o);
while (typeof argument[a] == 'string ') {
this.elements.push(d.getElementById(arguments[a]));
}
}
}


次に拡張しますそのためのいくつかの操作 DOM メソッド


get.prototype = {
each : function () {},
animate : function () {}
}


もちろん、このメソッドは jQuery とは異なりますが、理解できると思います。 jquery は可能です 次のようになります:


コードをコピーします コードは次のとおりです:
jQuery = window.jQuery = window. $ = function( selector, context ) {

return new jQuery.fn.init( selector, context );

jQuery. fn = jQuery.prototype = {
init: function( selector, context ) {}
}


次に、取得したキューに対するバッチ操作には必然的に各トラバーサル メソッドが必要になります。


コードをコピー コードは次のとおりです。 each : function (fn) {
for ( var i=0; ifn.call(this, this.elements[i])
}
return this;


それぞれは get.prototype によって拡張されたメソッドで、パラメーター関数を提供し、dom リストを走査し、関数を各要素にバインドします。次に、get.prototype を返すようにします。プロトタイプ自体には「スーパークラス」に似たプロパティがあるため、プロトタイプ オブジェクトに返されるメソッドはプロトタイプ拡張メソッドを引き続き呼び出すことができます。

この試みをより有意義にするために、次にアニメーション関数を作成しましょう。この関数は、JQuery が DOM を操作するための非常に一般的な方法であり、これを使用すると、ほとんどのアニメーションが非常にシンプルかつ簡単になります。以下は簡単な実装になります:



コードをコピーします
コードは次のとおりです:

animate: function (config) {
if (!this.animQueue) this.animQueue = HR._animQueue = [];
var a = 0、時間、トゥイーン、イーズ、コールバック;
while (引数[a]) {
if (引数の種類[a] == '数値') 時間 = 引数[a]
if (引数の種類[a] == '文字列') {
if (/^ease*/.test(arguments[a])) easy = argument[a];
else tween = argument[a];
if (HR.isFunction) (arguments[a])) callback = argument[a];
}

this.animQueue.push({
config: config,
time: time,
tween:トゥイーン、
ease: イーズ、
callback: コールバック
});
if (this.animQueue.length == 1) this.execute(this.animQueue); return this;
},


この段落を見ただけでは何もわからないかもしれません。jquery のようなシリアル メソッド チェーンを作成するには、一時キューが必要です。そうしないと、たとえメソッドチェーンが形成されても、これらのメソッドが並列してしまい、望む効果を達成できなくなります。したがって、上記のコードは主に animate をキューにプッシュするロジックを処理し、その後、最初のパラメータと最後のコールバックを除く他のパラメータをよりカジュアルに記述できるように、パラメータ引数についていくつかの判断を行います。位置を考慮する必要がなく、使いやすさが向上します。
コア変換関数が実行中です。



var _this = this, m = 0, n = 0,
_anim = function (el, key, from, to, at, tw,ease, cb) {
var isOP = (key == 'opacity' && !HR.support.opacity), _key = key;
if (isOP) {to = to*100;
var s = 新しい日付 ,
d = at,
b = parseFloat(from) || 0,
c = to-b;新しい日付 - s;
if (t >= d) {
t = d;
el.style[_key] = (isOP ? 'alpha(opacity=' : ' ') Tween .Linear(t, b, c, d) (key != 'opacity' ? 'px' : '') (isOP ? ')' : ''); cb && cb.apply (el) ;
if (m == n && _this.animQueue.length > 1) {
_this.animQueue(_this.animQueue); }

return;
}
el.style[_key] = (isOP ? 'alpha(opacity=' : '') Tween[tw][ease](t, b, c, d) ( key != 'opacity' ? 'px' : '') (isOP ? ')' : '');

if (!HR.timers[el.id]) HR.timers[ el.id ] = [];
HR.timers[el.id].push(setTimeout(arguments.callee, 16)); >_q = this.animQueue[0];

return this.each(function (el) {
for (var k in _q.config) {
m ;
_anim(el) ,
k,
k == 'opacity' && !HR.getStyle('filter', el) == '' 100 : parseInt(HR.getStyle('filter', el).match(/d{1,3}/g)[0]) : HR.getStyle(k, el),
_q.config[k],
typeof _q.time == '数値' ? _q .time : 1000,
typeof _q.tween == 'string' && !/^ease*/.test(_q.tween) : 'Quart',
typeof _q.tween == ' string' && /^ease*/.test(_q.ease) ? _q.ease : 'easeOut',
_q.callback)
}
}


このセクションはもう少し複雑に見えますが、最も基本的な変更は依然としてプライベート関数 _anim にあります。コードの残りの部分は基本的に、いくつかのバッチ操作、透明度の変更との互換性、および現在の変換が完了したかどうかを実行します。これら 2 つの段落を組み合わせることで、jquery のアニメーションの効果が基本的に実現されます。簡易版に属します。
もちろん、非常に重要な点を忘れてはなりません。つまり、変換できるので、変換を制御可能にするための stop メソッドが必要です。そうしないと、このコードの使いやすさが大幅に低下します。次のコード:




コードをコピー


コードは次のとおりです:


stop: function (clearQueue ) {
if (clearQueue) HR ._animQueue.length = 0;
this.each(function (el) {
if (!!HR.timers[el.id])
for ( var i=0; iこれを返します; 、

コードをコピー


コードは次のとおりです:

/* =========== animate js ============ */
/* @author:hongru.chen */
/* =================================== */

if (人事タイプ== '未定義' || !HR)
HR = {
extend : function (destination, source, override) {
if (override === #ff0000) override = true; (ソースの var プロパティ) {
if (オーバーライド || !(宛先のプロパティ)) {
宛先[プロパティ] = ソース[プロパティ]
}
}
宛先を返す;
}
};

(function () {

var Tween = { // 次の演算子のパラメータをそれぞれ表します: t: 実行時間、b: 開始amount、c: 合計変化、d: 合計時間
Linear: function(t,b,c,d){ return c*t/d b }、
Quad: {
easeIn: function(t , b,c,d){
return c*(t/=d)*t b;
},
easeOut: function(t,b,c,d){
return -c; * (t/=d)*(t-2) b;
},
easeInOut: function(t,b,c,d){
if ((t/=d/2) return -c/2 * ((--t)*(t-2) - 1) b;三次関数: {
easeIn: function(t,b,c,d){
return c*(t/=d)*t*t b;
easeOut: function(t, b ,c,d){
return c*((t=t/d-1)*t*t 1) b;
},
easeInOut: function(t,b,c,d) ) {
if ((t/=d/2) return c/2*((t-=2)*t*t 2; ) b;
}
},
Quart: {
easeIn: function(t,b,c,d){
return c*(t/=d)*t*t * t b;
},
easeOut: function(t,b,c,d){
return -c * ((t=t/d-1)*t*t*t - 1) b ;
},
easeInOut: function(t,b,c,d){
if ((t/=d/2) return -c/2 * ((t-=2)*t*t*t - 2)
}
},
Quint: {
easeIn: function (t,b,c,d){
return c*(t/=d)*t*t*t*t b;
},
easeOut: function(t,b,c, d ){
return c*((t=t/d-1)*t*t*t*t 1) b;
},
easeInOut: function(t,b,c,d) ) {
if ((t/=d/2) return c/2*((t-=2)* t *t*t*t 2) b;
}
},
Sine: {
easeIn: function(t,b,c,d){
return -c * Math . cos(t/d * (Math.PI/2)) c b;
},
easeOut: function(t,b,c,d){
return c * Math.sin(t/ d * (Math.PI/2)) b;
},
easeInOut: function(t,b,c,d){
return -c/2 * (Math.cos(Math.PI) * t/d) - 1) b;
}
},
Expo: {
easeIn: function(t,b,c,d){
return (t==0) ) ? b : c * Math.pow(2, 10 * (t/d - 1)) b;
},
easeOut: function(t,b,c,d){
return ( t ==d) ? b c : c * (-Math.pow(2, -10 * t/d) 1) b;
if (t==0) return b;
if (t==d) return b c;
if ((t/=d/2) return c/2 * (-Math.pow(2, -10 * --t) 2) b;
Circ: {
easeIn: function(t,b,c,d){
return -c * (Math.sqrt(1 - (t/=d)*t) - 1) b;
},
easeOut: function(t,b,c,d){
return c * Math.sqrt(1 - (t=t/d-1)*t) b; } ,
easeInOut: function(t,b,c,d){
if ((t/=d/2) return c/2 * (Math.sqrt(1 - (t-=2)*t) 1) b;
}
easeIn: function(t,b,c,d,a,p){
if (t==0) return b; if ((t/=d)==1) return b c; ! p) p=d*.3;
if (!a || a return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s) ) *(2*Math.PI)/p )) b;
},
easeOut: function(t,b,c,d,a,p){
if (t==0) return b; if ((t/=d)==1) return b c; if (!p) p=d*.3; a || a else var s = p/(2*Math.PI) * Math.asin (c/a); , -10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) c b);
},
easeInOut: function(t,b,c,d, a ,p){
if (t==0) return b; if ((t/=d/2)==2) return b c; if (!p) p=d*(.3*1.5) ;
if (!a || a else var s = p/(2*Math.PI) Math .asin (c/a);
if (t return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*( 2 *Math.PI)/p )*.5 c b;
}
},
戻る: {
easeIn: function(t,b,c,d,s){
if (s == 未定義) s = 1.70158;
return c*(t/=d)*t*((s 1)*t - s) b;
},
easeOut: function( t ,b,c,d,s){
if (s == 未定義) s = 1.70158;
return c*((t=t/d-1)*t*((s 1)* t s ) 1) b;
},
easeInOut: function(t,b,c,d,s){
if (s == 未定義) s = 1.70158; / =d/2) }
},
バウンス: {
easeIn: function(t , b,c,d){
return c - Tween.Bounce.easeOut(d-t, 0, c, d) b;
},
easeOut: function(t,b,c,d) {
if ((t/=d) return c*(7.5625*t*t) b;
} else if (t return c*(7.5625*(t-=(1.5/2.75))*t .75) b;
} else if (t return c *(7.5625*(t-=(2.25/2.75))*t .9375) b;
} else {
return c*(7.5625*(t-=(2.625/2.75))*t . 984375 ) b;
}
},
easeInOut: function(t,b,c,d){
if (t else return Tween.Bounce.easeOut(t*2-d, 0, c, d) * .5 c*.5 b;
}
}
}

var get = function (ids) {
var d = document, a = -1;
this.elements = [];
if (typeof ids != 'string' && !!ids.length) {
for (var i=0; ivar id = ids[i],ああ;
o = ID の種類 == '文字列' ? d.getElementById(id) : id;
this.elements.push(o);
}
} else {
while (typeof argument[a] == 'string') {
this.elements.push(d.getElementById(arguments[a]));
}
}
}

get.prototype = {

each : function (fn) {
for (var i=0; ifn.call(this, this.elements[i])
}
return this;
},

setStyle : function (p, v) {
this.each(function (el) {
el.style[p] = v;
});
これを返します;
},

show : function () {
var _this = this;
this.each(function (el) {
_this.setStyle('display', 'block');
})
return this;
},

hide : function () {
var _this = this;
this.each(function (el) {
_this.setStyle('display', 'none');
})
return this;
},

animate: function (config) {
if (!this.animQueue) this.animQueue = HR._animQueue = [];
var a = 0、時間、トゥイーン、イーズ、コールバック;
while (arguments[a]) {
if (typeof argument[a] == 'number') time = argument[a];
if (typeof argument[a] == 'string') {
if (/^ease*/.test(arguments[a]))ease = argument[a];
else トゥイーン = 引数[a];
}
if (HR.isFunction(arguments[a])) callback = argument[a];
}

this.animQueue.push({
config: config,
time: 時間,
tween: トゥイーン,
ease:ease,
callback:コールバック
});
if (this.animQueue.length == 1) this.execute(this.animQueue);

これを返します;
},

stop : function (clearQueue) {
if (clearQueue) HR._animQueue.length = 0;
this.each(function (el) {
if (!!HR.timers[el.id])
for (var i=0; i});
これを返します;
},

execute : function (queue) {
var _this = this, m = 0, n = 0,
_anim = function (el, key, from, to, at 、 tw、ease、cb) {
var isOP = (key == 'opacity' && !HR.support.opacity), _key = key;
if (isOP) {to = to*100; _key = 'filter'}
var s = 新しい日付、
d = at、
b = parseFloat(from) || 0、
c = to-b;

(function () {
var t = new Date - s;
if (t >= d) {
n ;
t = d;
el .style[_key] = (isOP ? 'alpha(opacity=' : '') Tween.Linear(t, b, c, d) (key != 'opacity' ? 'px' : '') (isOP ? ' )' : '');
!!cb && cb.apply(el);
if (m == n && _this.animQueue.length > 1) {
_this.animQueue.shift( );
_this.execute(_this.animQueue);
}

return;
el.style[_key] = (isOP ? 'alpha(opacity=' : '') Tween[tw][ease](t, b, c, d) (key != 'opacity' ? 'px' : '') (isOP ? ')' : ''); >if (!HR.timers[el.id]) HR.timers[el.id] = []
HR.timers[el.id].push(setTimeout(arguments.callee, 16)); 🎜>
})();
},
_q = this.animQueue[0];

return this.each(function (el) {
for (var k in _q.config) {
m ;
_anim(el,
k,
k == '不透明度' && !HR.support.opacity ? HR.getStyle('filter', el) == '' ? 100 : parseInt(HR.getStyle('filter', el).match(/d{1, 3}/g)[0]) : HR.getStyle(k, el),
_q.config[k],
typeof _q.time == 'number' _q.time : 1000,
typeof _q.tween == 'string' && !/^ease*/.test(_q.tween) ? _q.tween : 'Quart',
typeof _q.ease == 'string' && /^ease* /.test(_q.ease) ? _q.ease : 'easeOut',
_q.callback)
}
});
}
}

HR.extend(HR, {
get : function () {
return new get(arguments);
},
isFunction : function(o) {
return typeof(o) == 'function' && (!Function.prototype.call || typeof(o.call) == 'function');
},
getStyle : function (p, el) {
return el.currentStyle ? el.currentStyle[p] : document.defaultView.getComputedStyle(el, null).getPropertyValue(p);
support : ( function () {
try {
var d = document.createElement('div');
d.style['display'] = 'none';
d.innerHTML = '< a style="float:left; opacity:.5;">';
var a = d.getElementsByTagName('a')[0];
return {
opacity : a.style.opacity === '0.5'
}
}finally {
d = null
}
})(),

タイマー : { }

});
})();



次に、誰にとってもより直感的に理解できるようにするために、2 つのデモを作成しました
【demo1】

[Ctrl A すべて選択 注:
外部 Js を導入する必要がある場合は、更新して実行する必要があります
]
[デモ2]
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。