カスタムタグの利点、またはHTMLマークアップを放棄した方法

しばらくの間、 MaskJSライブラリを使用/開発してます。 最初はテンプレートのエンジンとしてのみ使用していましたが、やがてHTMLを完全に置き換えました。 記事では、アプリケーション開発、特にこの実装でコンポーネントアプローチが持つ利点を説明します。 ポイントで選択すると、およそ次のリストが得られます。



ライブラリ自体の詳細と例はこちら-libjs / Mask 、ソースはこちら-github / Mask



§スピード



  1. 性能


    それについてすぐに、それは常に最初の質問なので、すべての利点の長い説明の後、私は聞く-「まあ、あなたはあなたのDOMビルダーを通してそれを実装しました、これはすべておいしいですが、おそらくパフォーマンスが低下しますか?!」 したがって、このライブラリが現在使用しているライブラリよりもさらに高速であることをお約束します。 ポップな文でごめんなさい、たぶん私は間違っているかもしれませんが、もっと深く行きましょう。

    先ほど引用したjsperfのテストを分析しましょう。

    私は、自分のプロジェクトにとっても仕事にとっても、Webkit JavaScriptCoreとV8が重要であることに注意してください。 テストからわかるように、多くのブラウザでは、コンパイルとレンダリングが他のソリューションよりも進んでいます。

    コンパイルされたテンプレートをキャッシュするため、Mustacheはここで少し利点があります。



    コンパイル/解析テンプレート。 最初の勝利


    テンプレートから、 {tagName:'div',attr:{...},nodes:[...]}



    の形式のJSONツリーを構築します。 私の最初のアイデアは、クライアント用にテンプレートを準備することでした-将来のvar template = JSON.parse(serializedJsonDom)



    ために最後の1つ。 そのため、プリコンパイルはもはや無駄ではありません。



    DOMの構築。 二度目の勝利


    JSONツリーを受け取ったら、 DocumentFragmentを構築し、それを「ライブ」DOMに挿入します。 テストから、ここでパフォーマンスがレベル​​にあることは明らかです。 クリーンな.appendChild(documentFragment)



    を残して、 DocumentFragmentの作成におけるすべてのソルトを示しました。 繰り返しになりますが、興味深いことに、ここでも.innerHTMLはパフォーマンスが劣っています(Chrome)。



    重要な点は、最初にすべてを一度にレンダリングすることです。 jQueryウィジェットの例を見てみましょう。 いつものように、すべてが起こります:

    • レイアウトでは、コンテナ<div id='myWidget'></div>



      を指定します
    • javascript-e $('#myWidget').myWidgetInit(config);





    このアプローチの大きな欠点は、既製のDOM要素にウィジェットを作成することです。 そしてご存じのように、「ライブ」DOMの変更は比較的高価です。 そして、多くの場合、アプリケーションに複数のウィジェットがあることを認めなければなりません。



    これが、実際に非常に高速なDOM Builderです。



  2. 開発スピード


    これについては、次の段落でさらに詳しく検討しますが、実際には、このためにこの記事が考案されました。 ここで、任意のタグによって開発の速度と容易さが大幅に向上することに注意してください。 このレイアウトを考慮してください:

     header > menuBar { li target='item1' > 'Item1 Title' li target='item2' > 'Item2 Title' } viewsManager { view#item1 > carousel { img src='img1.png'; img src='img2.png'; } view#item2 > scroller { 'About Content' } }
          
          





    コンポーネントmenuBar, viewsManager, scroller, carousel slider



    が用意されている場合は、メニューとビューが切り替わり、 スクロールが動作して写真が回転するように、javascript-eに何かを記述する必要さえありません。 可愛いじゃない? そして、このレイアウトはありませんか? もちろん、多くのウィジェットは自己初期化もできますが、これは主にDom Readyイベントと必要なタグの検索/置換によって実装されます。これはすべて追加の「オーバーヘッド」です。 ここでは、すべてがこの同じDOM Builderを通過します。 このようなレイアウトはいつでも挿入でき、機能します。







§タグハンドラー



これらは私たちのコンポーネントです。 Builderがハンドラタグを検出すると、クラスオブジェクトを初期化し、レンダリングコンテキストをこのハンドラに渡します-魔法はありません。 タグの下に誰も登録されていない場合、彼は自分で要素を作成します。 コンポーネントを使用したより完全で便利な作業のために、小さな「抽象ではなく」クラスCompo( SourcesDocumentation )もあります。



§プリプロセッサ



ツリーのようなレンダリングフローがある場合、レンダリングとレイアウト全体に影響を与える強力なツールが得られます。 下のレイアウトを変更するプリプロセッサコンポーネントを呼び出します。 したがって、コンポーネントをレイアウトに導入します-自由裁量で、下のテンプレートを修正するか、モデルの入力データを置き換えてレンダリングを続行します。 これは、さまざまなレイアウトを構築するための非常に便利なパターンです。 MasterPages(asp.net hello)の例を次に示します。

 layout:master#twoColumnLayout { div.wrap { div.layoutLeft > placeholder#left; div.layoutLeft > placeholder#right; } } layout:view master='twoColumnLayout' { left { /** content */ } right { /** content */ } }
      
      





コンポーネント#twoColumnLayoutはもちろんそのスタイルを追加でロードする必要がありますが、別の時間にはそれ以上です。

これは非常に単純な例ですが、ここでは、どのように基本的な表現を別のテンプレートに置き換えることができるかを見ることができます。 実装例-layout.js



§ポストプロセッサー





デコレータとも呼ばれます。 ここでは、テンプレートはプロレンダラーであるため、親ではなく親を変更していますが、直接HTMLElement



(DocumentFragmentを使用しているため、すべての変更が簡単です)。 このアプローチは、強力な設計アシスタントでもあります。 バインダーの例:

 div { bind value='name'; bind value='status' attr='class'; }
      
      





ここで、ポストプロセッサはモデルをdiv



要素に関連付けます。

 var person = { name: "Alex", status: "happy" } container.appendChild(mask.renderDom(template, person)); setTimeout(function(){ person.status = 'busy' ; person.name="Anonym" }, 1000);
      
      





コードは明確だと思います。 そして、実装はここで見ることができます-github



§制御の反転(依存性注入)



段落のタイトルで申し訳ありません-「本当に痛々しいほど強い」という名前は次のようなものです。 えー、それは…のように聞こえます。その名前のように、私はパターンがあまり好きではありません-あなたは力を感じます。 歌詞がすみません、抵抗できませんでした。 このトピックに戻ると、任意のタグは、新しいパターンや忘れられがちな古いパターンの地平を開いていると言えます。

たとえば、プロパティエディタのファクトリを実装する計画:

 form { propertyEditor value='name'; propertyEditor value='birthday'; propertyEditor value='age'; }
      
      





そして、実装は次のようになります。

 mask.registerHandler('propertyEditor', Class({ render: function(values, container, cntx){ var value = Object.getProperty(values, this.attr.value), template; switch(Object.typeOf(value)){ case 'string': template = Object.format('input type="text" value="#{%1}" > bind value="#{%1}" prop="value";',this.attr.value); break; case 'datetime': template = Object.format('datePicker date="%1";', value.toString()); break; /**    */ } mask.renderDom(template, values, container, cntx); }); }}
      
      







ここで重要な点は、同じ「DIV」でもタグを再定義することでテンプレートに自分自身を埋め込むことができるということです。これにより、無制限の視野が広がり、プレゼンテーション、テスト、その他思い浮かぶことを操作できます。



§断熱



任意のタグ、またはむしろそのハンドラーは、適切な分離に役立ちます。 ブロックを構成する必要があるため、任意のブロックを個別のプロジェクトに割り当て(分解)、開発、テスト、および接続し直すことができます。 たとえば、上記の例から「カルーセル」コンポーネントがない場合、メインプロジェクトを閉じ、その子(画像)を回転させるコンポーネントを開発し、メインプロジェクトに戻って接続します。 ローダーは、補助画像やスタイルなど、コンポーネントに必要なすべてのリソースをロードできる必要があります。 ブートローダーについてはすでに話しましたが、興味深いアイデアがいくつか出てきたので、もう少し言いたいと思います。 しかし、これは次の記事にあります。

分離は、開発プロセスだけでなく、アプリケーションアーキテクチャでも重要です。 これは、イベントモデルによって実現されます。



§マークアップ-モデル-コード-スタイル



私はWebプログラミング(マークアップ-コード-スタイル)の構造が本当に好きなので、MaskJSに固執しようとしました-マークアップからロジックをできるだけ削除し、レイアウトとデータに焦点を当てました。 他のテンプレートエンジン-ループ、条件、式などを見てください。 私はそれを持っている方がはるかに良いようです(コードはなく、レイアウトのみがあります):

 ul > list value='users' > li > '#{name}'
      
      





タグ(コンポーネント) list;



テンプレートに渡されたモデルから"users"



配列を取得し、そのテンプレートli > "#{name}"



N(users.length)回複製します。 他のすべてはコンポーネントを介して実装することも、既成のソリューションを利用することもできます。 したがって、レイアウトはレイアウト、コードはコード、スタイルはスタイルです。 これらはすべて、最小限に絡み合っている必要があります。 もちろん、これはすべて主観的なものであり、おそらく私は根本的に間違っているのかもしれません。



§HTMLの回避



上記のすべてについて、プレーンHTMLの作成を完全に拒否しました。 このページには、コンテンツがDOMでレンダリングされる「マスク/テンプレート」タイプのスクリプトタグがあります。 便宜上、たとえば、 TimePickerのように、多くの既製のライブラリをコンポーネントにラップしようとしています。



私が誰かを怒らせたり、どこかで間違えられたりした場合は謝罪します。 Chromeには優れたスペルチェッカーがありますが、句読点の助けにはなりませんが、おそらく「ああ、どうあるべきか」です。



良い一日を!



All Articles