(アーカイブ)Matreshka.js v0.2

この記事は古くなっています。 現在のバージョン履歴を参照してください。





みなさんこんにちは。 Matreshka.jsフレームワークの次のバージョン0.2への更新を紹介します。 マトリョーシカは、オープンソースコードを備えた汎用フレームワークであり、そのイデオロギーは外観よりもデータの優位性です:インターフェースがデータと同期する方法のルールを設定し、インターフェースイベントがデータに関係しない場合を除き、データのみで動作します、ボタンをクリックするか、フォームを送信するだけでは、データは変更されませんが、関数が起動され、データが処理されます)







Matryoshkaを使用すると、データとプレゼンテーションのさらなる同期を心配することなく、データとプレゼンテーション要素(オブジェクトのプロパティや入力フィールドの値など)を関連付けることが非常に簡単になります。 たとえば、最も単純なバインディングは次のようになります。

<select class="my-select"> <option>1</option> <option>2</option> <option>3</option> </select>
      
      





インスタンスを作成します。

 var mk = new Matreshka();
      
      





xプロパティを.my-select



要素に.my-select





 mk.bindElement( 'x', '.my-select' );
      
      





データを変更する

 mk.x = 2;
      
      





プロパティxに異なる値を割り当てた後、それに応じて要素の状態が変化します。

ライブ例をご覧ください



入れ子人形のもう1つの重要な機能は、イベント(カスタムイベントを含む)です。 たとえば、マトリョーシカはプロパティの値の変化をキャッチできます。

 mk.on( 'change:x', function( evt ) { alert( 'x   ' + evt.value ); });
      
      





コードは"x "



を出力します。

 mk.x = '';
      
      





これらおよびその他の機能の詳細については、上記のリンクを参照してください。



マトリョーシカのウェブサイトへのリンクgithubリポジトリにリンクします



AMDサポート



Matryoshkaは、非同期モジュール定義仕様をサポートするようになりました。 言い換えれば、マトリョーシカはrequirejsのようなライブラリーと互換性があります。 これは、グローバル名前空間を損なうことなく、tru-codeを記述できるようになったことを意味します。 2つの接続タイプがサポートされています。名前付きモジュール要求と名前なしモジュール要求です。



名前付きモジュール:

 requirejs.config({ paths: { xclass: 'path/to/matreshka', matreshka: 'path/to/matreshka' } }); require(['xclass', 'matreshka'], function(Class, MK) { return Class({ 'extends': MK //... }); });
      
      





しかし、これはむしろ新しいプロジェクトファイル構造を使用することの副作用です。 そして、推奨される方法は、名前のないモジュールをリクエストすることです:

 require(['path/to/matreshka'], function( MK ) { return MK.Class({ 'extends': MK // ... }); });
      
      





ご覧のとおり、MatryoshkaにはClass



プロパティが含まれています。これは、クラスを作成する関数を複製します。追加のモジュールを要求する必要はありません。



Matreshkaメソッド#addDependency :新しい名前と追加機能



1. addDependence



のプロンプトでaddDependence



メソッドの名前がaddDependency



に変更されaddDependency



た(彼に感謝します)。古いメソッドは「非推奨」とマークされています。

2.メソッドは、他のクラスのプロパティに依存関係を追加する約束された機能をサポートするようになりました。 2番目の引数の構文は次のとおりです。 [ , "", , "", , "" ... ]



-奇数要素を持つ配列-クラスのインスタンス、偶数-これらのインスタンスのキー。目的のプロパティが依存します。 例を見てみましょう:

 this.addDependency( 'a', [ anotherInstance1, 'b', this, 'c', anotherInstance2, 'd' ], function( b, c, d ) { return b + c + d; });
      
      





ここで、プロパティ"a"



"b"



は、 anotherInstance1



オブジェクトのプロパティ"b"



anotherInstance1



オブジェクトのプロパティ"d"



anotherInstance2



および独自のプロパティ"c"



依存します。 古い構文は引き続き機能します。

 this.addDependency( 'a', 'b c', function( b, c ) { return b + c; });
      
      





3.安全な中毒。 この点は構文に影響を与えません。このリリース以降、 addDependency



使用された場合、メソッドは無限ループを回避します。 プロパティ"b"



がプロパティ"b"



依存し、プロパティ"b"



がプロパティ"c"



依存し、プロパティ"c"



が順番に"b"



依存する状況を想像してください。 たとえば、抽象的な図:

 this.addDependency( 'a', 'b', function( b ) { return b * 2; }); this.addDependency( 'b', 'c', function( c ) { return c * 3; }); this.addDependency( 'c', 'a', function( a ) { return a / 5; });
      
      





このコードの各依存関係により、次の原因が生じ、結果としてページがぶら下がります。 このようなエラーに対する保護が登場しました。コードは依存関係のチェーン全体に特別なフラグを渡し、フレームワークが潜在的に危険な依存関係に達するとチェーンが停止します。 新しいフォームのaddDependency



を使用すると、複雑な(またはそうではない)数式に基づいて相互依存関係を構築できます。これらの数式の実装にエラーが生じる心配はありません。 辺の長さで長方形の周囲を計算し、辺の長さを計算する例:

 this.addDependency( 'p', 'a b', function( a, b ){ return (a + b) * 2; }); this.addDependency( 'a', 'p b', function( p, b ){ return p/2 - b; }); this.addDependency( 'b', 'p a', function( p, a ){ return p/2 - a; });
      
      







静的メソッドMatreshka.procrastinate



次の状況を想像してください(私の練習から取られます)。 チェックボックスなど、いくつかのテキストフィールドを持つフォームがあります。フォーム要素の1つの値が変更されると、アプリケーションはサーバーにリクエストを送信する必要があり、サーバーは3つのグラフをレンダリングするためのデータを返します。 グラフの描画はプロセッサにとって難しいタスクであり、弱いコンピューター( Highchartsなど) では0.5秒かかります。 退屈していて、チェックボックスを繰り返しクリックすることにしたユーザーを想像してください。 どうなるの? 多数のリクエストが送信され、多数の回答が返されます。これにより、グラフが何度も描画されます。 この場合、彼らは通常何をしますか? サーバー要求をキャンセルします。 問題は、落ち着くまで待つことができるのに、なぜこのリクエストが送信されたのかということです。 :)



この問題を解決するために、最も単純な関数(おそらく自転車)を使用しました。この関数は引数として別の関数を取り、その変更を返します。この関数は一定期間に1回しか実行できません。 それなしでは単一のプロジェクトではできないため、マトリョーシカコードに含めることが決定されました。 例:

 var doSomethingHeavy = function( i ) { console.log( 'Ok', i ); }; var procrastinateSomethingHeavy = MK.procrastinate( doSomethingHeavy ); for( var i = 0; i < 100; i++ ) { procrastinateSomethingHeavy( i ); } // >> Ok 100
      
      





機能コード(マトリョーシカ以外で使用したい場合):

 var procrastinate = function ( f, d, thisArg ) { var timeout; if( typeof d !== 'number' ) { thisArg = d; d = 0; } return function() { var args = arguments, _this = this; clearTimeout( timeout ); timeout = setTimeout( function() { f.apply( thisArg || _this, args ); }, d || 0 ); }; };
      
      





このメソッドは、「処理する」関数に加えて、遅延とコンテキストを引数として取ります。 遅延は、次に呼び出されたときに実際の関数呼び出しが何ミリ秒遅延するかを決定します。



そして、これは関数を決して呼び出さない場合の例です(理解を深めるため)。

 var procrastinateSomethingHeavy = MK.procrastinate( function() { console.log( 'Ok' ); }, 1000 ); setInterval( function() { procrastinateSomethingHeavy(); }, 500 ); //   
      
      







新しいバインドキーのinitialize





バインダーは、 Matreshka #bindElementメソッドの 3番目の引数です。 覚えている場合、これは3つのプロパティで構成されるオブジェクトです: on



(プロパティを更新するDOMイベントによって)、 getValue



(要素からプロパティの値を抽出する方法)、 setValue



(プロパティの値を要素に設定する方法)。 詳細はこちらをご覧ください (ところで、マトリョーシカに関するすべての記事はリリースごとに更新され、関連資料です)。 現在、別のオプションのプロパティinitialize







initialize



は、バインディング中、またはその前に開始する関数です。 関数のタスクはコードを甘くすることです。 最初の記事の例をご覧ください

まず、バインドする前に、スライダーを宣言します。

 <div class="slider"></div>
      
      





 $( ".slider" ).slider({ min: 0, max: 100 });
      
      





次に、マトリョーシカのインスタンスを宣言します。

 var mk = new Matreshka();
      
      





次に、バインディングを呼び出します。

 mk.bindElement( 'x', '.slider', { on: 'slide', // ,       getValue: function() { return $( this ).slider( 'option', 'value' ); //      (.  jQuery ui.slider)? }, setValue: function( v ) { $( this ).slider( 'option', 'value', v ); //      (.  jQuery ui.slider)? } });
      
      





コードはやや冗長です。 slider



クラスを使用して要素に2回アクセスします(最初にプラグインを使用してから、要素をバインドします)。 これは回避できます:

 var mk = new Matreshka(); mk.bindElement( 'x', '.slider', { initialize: function() { $( this ).slider({ min: 0, max: 100 }); }, on: 'slide', getValue: function() { return $( this ).slider( 'option', 'value' ); }, setValue: function( v ) { $( this ).slider( 'option', 'value', v ); } });
      
      







Matreshka#defineSetterメソッド



ご想像のとおり、この新しいメソッドはプロパティのセッターを定義します。

 this.defineSetter( 'x', function( value ) { return alert( value ); });
      
      





メソッドを使用する場合、組み込みのプロパティセッター(存在する場合)をグラインドし、プロパティ変更イベントが機能しないことを覚えておく必要があります。



 this.x = 1; this.on( 'change:x', function( evt ) { // ,    -   alert( 'x is changed to ' + evt.value ); }); this.defineSetter( 'x', function() { // ... }); this.x = 2;
      
      







イベント名の新しい構文:プロパティおよびコレクションアイテムのイベントハンドラーの追加



おそらく、このリリースで最も重要なことは、インスタンスの内部コンテンツにイベントハンドラーを追加する機能です。



イベント"@_"





プロパティ値がMatryoshkaのインスタンスである場合、 Matryoshkaから継承したクラス( MK.ObjectおよびMK.Arrayを含む)内にプロパティのハンドラーを追加できるようになりました。 例を見てみましょう:

 var mk = new MK; mk.on( 'x@yeah', function() { alert( 'yeah' ); }); mk.x = new MK; mk.x.trigger( 'yeah' );
      
      





プロパティが定義される順序、およびハンドラーをアタッチするときは重要ではないことに注意してください。最初にイベントハンドラーを追加してから、プロパティを宣言できます。 さらに、プロパティの値が変更された場合、ハンドラーは新しい値に対してのみ機能し、古い値に対してはハンドラーが削除されます。



MK.Object



イベント"@_"





このイベント名を使用すると、 MK.Object



インスタンスのJSONキーのハンドラーを追加できます(JSONキーまたはデータを担当するキーについては、MK.Objectに関する記事を参照してください )。

 var mkObject = new MK.Object; mkObject.on( '@yeah', function() { alert( 'yeah' ); }); mkObject.jset( 'x', new MK ); mkObject.x.trigger( 'yeah' );
      
      





プロパティが宣言される順序とイベントハンドラーも重要ではありません。



MK.Array



イベント"@_"





MK.Object



と同様に、 MK.Object



も同じ機会があります。この要素がMK.Object



からMK.Object



いる場合、ハンドラーは配列の任意の要素にハングアップします。

 var mkArray = new MK.Array; mkArray.on( '@yeah', function() { alert( 'yeah' ); }); mkArray.push( new MK ); mkArray[ 0 ].trigger( 'yeah' );
      
      





これらの3つの変更は、 "yeah"



イベントをリッスンするだけでなく、 "change:"



などの他のイベントも安心してリッスンできます"change:"





 this.on( 'x@change:y', function() { /* ... */ } ); this.on( '@change:y', function() { /* ... */ } );
      
      





理論的には、この機能を使用すると、データツリーの深部にある他のイベントをリッスンすることで、凝ったイベント名を作成できます。 オブジェクトとして表現できるデータ構造があるとしましょう:

 { a: [{ b: { c: { e: 1 } } }, { b: { d: { e: 2 } } }] }
      
      





"e"



プロパティの変更の最後に到達するには、次のようなハンドラーを追加できます。

 this.on( 'a@@b@@change:e', function() { /* ... */ } );
      
      







Matreshka#$ boundメソッド



マトリョーシカには、バインドされた要素を返す2つのメソッドがあります。最初のバインドされた要素またはnull



を返すMatreshka#boundと 、バインドされた要素のコレクションを返すMatreshka#boundAllです。 これは、「コレクション」という用語を理解し、ドルを知ることに慣れている、 VanillaJSに精通していないjQueryを使用する初心者に問題を引き起こす可能性があります。 したがって、 $bound



メソッドがフレームワークに追加され、 Matreshka#boundAllとまったく同じことを行いました



 this.bindElement( 'a', '#x, #y' ); this.$bound( 'a' ).animate( /* ... */ ); //   jQuery 
      
      







その他の変更



usejQueryuseBalalaika



代わりにMatreshka.useAs $


バージョン0.1から、マトリョーシカはjQueryがページ上にない場合、Balaalaikaマイクロライブラリを使用してjQueryのハード依存関係を取り除きました。 この変更の結果は、jQueryの存在に関係なく、 usejQuery



メソッド(jQueryがuseBalalaika



後に接続された場合)とuseBalalaika



(jQueryがuseBalalaika



前に接続された場合)を使用して、 usejQuery



2つのライブラリのいずれかを使用する2つのメソッドの作成でしたただし、組み込みライブラリを引き続き使用する必要があります)。 今では、jQueryのようなライブラリを一般に使用できるメソッドが踊っています( usejQuery



useBalalaika



は非推奨としてマークされています)。



使用例:

 MK.useAs$( jQuery ); MK.useAs$( jQuery.noConflict() ); MK.useAs$( Zepto ); MK.useAs$( MK.$b ); // 
      
      





この変更の結果、マトリョーシカは、ロードして、jQueryのみを使用する代わりに、ドル記号ライブラリが存在し、特定のメソッドがあればそれを使用します。 プロジェクトファイルのソースコードのどのメソッドを正確に見つけることができます



Xclass.sameメソッド


クラスにシタックスシュガーを追加する小さな変更( 継承に関する記事を参照)。 多くの場合、クラスを作成するとき、このクラスのコンストラクターは、独自のコンテキストで親のコンストラクターを呼び出すだけで済みます。

 var MyClass = Class({ 'extends': AnotherClass, constructor: function() { AnotherClass.call( this, arguments ); }, someNewMethod: function() { /* ... */ } });
      
      





同じことがより簡潔にできるようになりました。

 var MyClass = Class({ 'extends': AnotherClass, constructor: AnotherClass.same(), someNewMethod: function() { /* ... */ } });
      
      







要素がバインドされる前にDOMイベントハンドラー(たとえば、 "click::x"



)を追加する


Matryoshkaには、 Matreshka#onメソッドを使用して、添付された要素にイベントハンドラーを添付する機能があります。

 this.bindElement( 'x', '.my-element' ); this.on( 'click::x', function() { alert( '.my-element is clicked' ); });
      
      





問題は、要素がバインドされる前にコレクションDOMハンドラーを追加できなかったことです。 bind



イベントを待って、このイベントが発生したときにハンドラーを追加することで、倒錯する必要がありました。

 this.on( 'bind:x', function() { this.on( 'click::x', function() { alert( '.my-element is clicked' ); }); }); this.bindElement( 'x', '.my-element' );
      
      





これで、DOMイベントのバインド/追加の順序は重要ではなくなりました。

 this.on( 'click::x', function() { alert( '.my-element is clicked' ); }); this.bindElement( 'x', '.my-element' );
      
      







バグ修正/リファクタリング



  • Matreshka.Array#initializeSmartArray (操作中のメソッドのドキュメント)がthis



    返すthis



  • Matreshka.Array#createFromは引数としてundefined



    を取ります
  • Matreshka.Arrayクラスに対して"modify"



    イベントが発生"modify"



    ケースを変更しました
  • Matreshka.Array



    は同じ名前のイベントがありますが、別の場合に発生するため、プロパティが"remove"



    ではなく削除されると、 Matreshka.Array



    "delete"



    イベントを発生させるようになりました
  • [].forEach



    が存在しない場合、 es5-shimを有効にするための提案とともにエラーが生成されます
  • バラライカパーサーのバグを修正
  • Matreshka#一度のメソッドのバグが修正され、 Matreshka#offメソッドを使用してハンドラーを削除できるようになりました
  • トライアドeventName + eventHandler + context



    は、インスタンスごとに1回のみ追加できるようになりました
  • Class



    関数のバグを修正( splice



    vs slice



  • Matreshka#onおよびMatreshka#offメソッドのリファクタリング
  • 小さなリファクタリングMatreshka#トリガーMK#セット




次は?



1.次の記事では、TodoMVCの実装について紹介します。 記事の準備はできていますが、編集が必要です。 実装も準備ができていますが、ドキュメントは更新されています。

2.その後、 MK.Array



に関する大きな記事が計画され、以前の記事が置き換えられます。 そこで、メソッド、配列の要素がレンダリングされる方法、「モデル」、および配列メソッドにオプションを渡す方法について詳しく説明します。

3.既にテストされている多数の興味深い変更を含むバージョン0.3。 いつものように、記事があります。



その後、テキストのコーミングや英語に関連するエラーの修正など、ドキュメントの大規模なレビューが行われます。 メインページ「マトリョーシカを選ぶ理由」 ページのテキストは既に修正されいます。



すべてに良い!



All Articles