ReactとAngularをクロスするとどうなりますか?







Akiliは、React、Angular、Aureliaなどのソリューションの影響下で出現したjavascriptフレームワークです。 目標は、私が見た最高のものをすべて組み合わせ、可能な限りすべてを簡素化することでした。



Reactに似ていますが、JSXを撃退しますか? Angularが大好きですが、すべての魔法にうんざりしていませんか?



次に、これを試してください。



私は物事を整理するための最良の方法は練習であると確信しています。 したがって、例からすぐに説明を始めます。 これらは、Babel(es2015 + stage-0)を使用してコードをコンパイルしているように書かれています。



最初のステップ



import Akili from 'akili'; class MyComponent extends Akili.Component { constructor(el, scope) { super(el, scope); scope.example = 'Hello World'; } } Akili.component('my-component', MyComponent); //   document.addEventListener('DOMContentLoaded', () => { Akili.init(); //   });
      
      





 <body> <my-component>${ this.example }</my-component> </body>
      
      





ここで、最初のコンポーネントを作成して登録し、アプリケーションを初期化しました。 通常のコンポーネントアプローチは一見しただけですが、すぐにいくつかの点に注目したいと思います。



まず、コンポーネントのスコープはマークアップのスコープから分離されます。 つまり、コンポーネントを安全に継承でき、このマークアップには影響しません。



 class MySecondComponent extends MyComponent { constructor(...args) { super(...args); this.scope.example = 'Goodbye World'; } myOwnMethod() {} } Akili.component('my-second-component', MySecondComponent)
      
      





 <body> <my-component>${ this.example }</my-component> <my-second-component>${ this.example }</my-second-component> </body>
      
      





スコーププロパティは、 スコープコンポーネントのプロパティです。 これは、必要なデータを入力し、 ${ this.example }



形式の式を使用してテンプレートに表示できる特別なオブジェクトです。 これはこのスコープです。 実際、javascript式は括弧で囲むことができます。



次に、マークアップスコープも継承されます。 最初のコンポーネントのスコープに新しい値を追加します。



 class MyComponent extends Akili.Component { constructor(el, scope) { super(el, scope); scope.example = 'Hello World'; scope.test = 'Test'; } }
      
      





次に、以下のマークアップ:



 <body> <my-component> <b>${ this.example }</b> <my-second-component>${ this.example } - ${ this.test }</my-second-component> </my-component> </body>
      
      





コンパイル後、次のようになります。



 <body> <my-component> <b>Hello World</b> <my-second-component>Goodbye World - Test</my-second-component> </my-component> </body>
      
      





第三に、コンポーネントロジックとそのテンプレートの同期は、いつでもスコープ変数を変更することによってのみ発生します。



 class MyComponent extends Akili.Component { constructor(...args) { super(...args); this.scope.example = 'Hello World'; setTimeout(() => { this.scope.example = 'Goodbye World'; }, 1000); } }
      
      





しばらくすると、オブジェクトとテンプレートの両方で変数の値が変化します。



Reactと比較したライフサイクルの概要



.constructor(el、スコープ)

まず、コンポーネントは単純なjavascriptクラスであるため、コンストラクターが呼び出されます。 コンポーネントとスコープオブジェクトがバインドされる要素をhtml引数で受け取ります。 ここでは、必要に応じて、 .cancel()メソッドを呼び出して、要素に変更を加えたり、コンパイルをキャンセルしたりできます。



.created()

コンポーネントのコンパイルがキャンセルされていない場合は、ここにアクセスします。 このメソッドは、実際にはコンストラクターと違いはありません。 Reactでは、同様の機能がcomponentWillMountによって実行されます



.compiled()

ここでは、コンポーネントがコンパイルされます;テンプレートでは、式の代わりに、対応する値が既にあります。

Reactでは、これはcomponentDidMountです。 この時点でコンパイルされることが保証されているすべての親要素にもアクセスできます。



.resolved()

私の知る限り、この方法は私に知られているフレームワークに類似していません。

実際、Akiliでは、必要に応じてコンパイル時に非同期操作を使用できます。 これらには、いくつかのシステム操作およびカスタム操作が含まれます。 たとえば、ファイルからコンポーネントテンプレートをロードする場合:



 class MyComponent extends Akili.Component { static templateUrl = '/my-component.html'; constructor(...args) { super(...args); this.scope.example = 'Hello World'; } }
      
      





または、自分で実行する非同期操作:



 class MyComponent extends Akili.Component { static templateUrl = '/my-component.html'; constructor(...args) { super(...args); this.scope.example = 'Hello World'; } compiled() { return new Promise((res) => setTimeout(res, 1000)); } }
      
      





コンパイルされたメソッドでは、promiseを返すことができます。 解決すると、すべての非同期操作が完了するまで待機します。 この場合、コンパイル自体は同期的に行われます。



つまり、 解決されたメソッドでは、非同期操作を含むものを含め、あらゆるレベルのネストのすべての子が確実にコンパイルされます。



.removed()

コンポーネントが削除されたときに呼び出されます。 アナログはcomponentDidUnmountです。



.changed(キー、値)

コンポーネントの属性が変更されたときに呼び出されます。 アナログはcomponentWillReceivePropsです。

これはフレームワークの非常に重要な部分であるため、以下の別のセクションで詳細に説明します。



汎用性、絶縁性、コンポーネントのモジュール性



コンポーネントを完全に分離でき、外部条件にまったく依存しないことが非常に重要です。 そのようなコンポーネントの例を次に示します。



 import Akili from 'akili'; class NineComponent extends Akili.Component { static template = '${ this.str }'; static define() { Akili.component('nine', NineComponent); } constructor(...args) { super(...args); this.scope.str = ''; } compiled() { this.attrs.hasOwnProperty('str') && this.addNine(this.attrs.str); } changed(key, value) { if(key == 'str') { this.addNine(value); } } addNine(value) { this.scope.str = value + '9'; } }
      
      





前の例に追加します。



 import NineComponent from './nine-component'; NineComponent.define(); Akili.component('my-component', MyComponent); document.addEventListener('DOMContentLoaded', () => { Akili.init(); });
      
      





 <body> <my-component> <nine str="${ this.example }"></nine> </my-component> </body>
      
      





したがって、コンパイル後に得られるものは次のとおりです。



 <body> <my-component> <nine str="Hello World">Hello World9</nine> </my-component> </body>
      
      





NineComponentは完全に分離されていることがわかりました。 それは、ある種の引数を取り、それらで何かをすることができる関数のように見えます。 この場合、送信された文字列の最後に番号9を追加して表示します。



Akiliの属性とReactのプロパティの類似性を描くことができます。

this.attrs => this.props



。 それらは同じ役割を果たしますが、わずかな違いがあります。



Akiliでは、 スコープと同様にattrsプロパティはプロキシです。つまり、要素のhtml属性を追加、変更、または削除し、このオブジェクトの一部のプロパティで対応する操作を実行できます。 Attrsオブジェクトプロパティは、要素の属性と同期されます。



バインドに属性を使用できます。 上記の例では、MyComponentコンポーネントのスコープ変数this.exampleが 変更されると、NineComponentの変更されたメソッドが呼び出されます。 このために特別なことを行っていないことに注意してください。 str属性の式は、テンプレートの値を単に表示した最初の例と違いはありません。



便宜上、 changedの短縮バージョンを使用できます。



 class NineComponent extends Akili.Component { changed(key, value) { if(key == 'str') { this.addNine(value); } } }
      
      





 class NineComponent extends Akili.Component { changedStr(value) { this.addNine(value); } }
      
      





上記の例は同等です。 大量のifやcaseを生成しないために、適切なメソッドをすぐに記述する方が簡単です。 命名の原則は単純です: 変更された+大文字の属性キャメルケースの名前



イベント



ここではすべてが簡単で、 onのダッシュを追加すると、すべてが通常通りになります。 最初の例を変更します。



 class MyComponent extends Akili.Component { static events = ['timeout']; constructor(...args) { super(...args); this.scope.example = 'HelloWorld'; this.scope.sayGoodbye = this.sayGoodbye; } compiled() { setTimeout(() => this.attrs.onTimeout.trigger(9), 5000); } sayGoodbye(event) { console.log(event instanceof Event); // true this.scope.example = 'Goodbye World'; } }
      
      





 <body> <my-component on-timeout="${ console.log(event.detail); // 9 }"> <button on-click="${ this.sayGoodbye(event) }">say goodbye</button> ${ this.example } </my-component> </body>
      
      





イベントシステムはネイティブに基づいています。 上記の例は、カスタムイベントを作成およびトリガーできることも示しています。



配列を操作する



 class MyComponent extends Akili.Component { constructor(...args) { super(...args); this.scope.data = []; for (let i = 1; i <= 10; i++) { this.scope.data.push({ title: 'value' + i }); } } }
      
      





 <my-component> <for in="${ this.data }"> <loop>${ this.loopIndex } => ${ this.loopKey} => ${ this.loopValue.title }</loop> </for> </my-component>
      
      





 <my-component> <ul in="${ this.data }"> <li>${ this.loopValue }</li> </ul> </my-component>
      
      







オプショナル



Akiliには、ルーター、ajaxリクエストを作成するためのライブラリ、ループを処理するための多くのシステムコンポーネント、フォーム、 サーバーレンダリングを強化する機能などが備わっており、詳細な説明はドキュメントに記載されています



この記事はAkiliを紹介するために書かれたものであり、いくつかの技術的な問題を全体として明らかにしようとしましたが、フレームワークに含まれているものの5分の1でもここに収まりません。 ドキュメントにはさらに多くの情報があります。興味がある場合は、他の記事でトピックをさらに広げていきます。



フレームワークはまだベータ版です。試してみてください。



All Articles