19

次のようなデータがあるとしましょう

var data = {
  facets: [{
    name : "some name",
    values: [{
      value: "some value" 
    }]
  }]
};

これは、次のようにノックアウトテンプレートにバインドされたビューモデルとして簡単に表すことができます。

<ul data-bind="foreach: facets">    
  <li>      
    <span data-bind="text: name"></span>
    <ul data-bind="foreach: values">            
      <li data-bind="text: value"></li>     
    </ul>
  </li>
</ul>

問題は、プログレッシブエンハンスメントを使用したときに同じ結果をどのように達成できるかということです。つまり、最初にサーバー側でテンプレートをレンダリングしてから、ノックアウトテンプレートとビューモデルをそのレンダリングにバインドします。

単純なサーバー側のテンプレートは次のようになります。

<ul>    
  <li>      
    <span>some name</span>
    <ul>            
      <li>some value</li>       
    </ul>
  </li>
</ul>

私はいくつかの異なる可能性を探求しました:

  • 1つは、1つのノックアウトテンプレートと1つのサーバー側テンプレートを作成し、サーバー側テンプレートのDOMを解析することによって動的にノックアウトビューモデルを生成することです。このように、JavaScriptが有効になっている場合はノックアウトテンプレートのみが表示され、JavaScriptが無効になっている場合はサーバー側のテンプレートのみが表示されます。それらは、同じように見えるようにスタイルを設定できます。

  • 別のアプローチは、ファセット配列内の各アイテムのバインディングを、そのファセットの既存のDOM要素に個別に適用することです。ただし、これはまだ1レベルの深さであり、ネストされた要素では機能しません。

これらのアプローチはどちらもかなりクリーンではないようです。別の解決策は、レンダリング全体を処理し、可能であれば既存の要素を再利用するカスタムバインディングを作成することです。

他のアイデアはありますか?

4

5 に答える 5

4

ここで説明するように、最初の要素から匿名のテンプレートを生成するなど、いくつかのアプローチを検討しました。

http://groups.google.com/group/knockoutjs/browse_thread/thread/3896a640583763d7

または、次のようなカスタム バインディングを使用して、配列の各要素に対して個別のバインディングを作成します。

ko.bindingHandlers.prerenderedArray = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
        var binding = valueAccessor();              
        binding.firstTime = true;

        $(element).children().each(function(index, node) {                  
            var value = ko.utils.unwrapObservable(binding.value)[index];                        
            ko.applyBindings(value, node);
        }); 

        return { 'controlsDescendantBindings': true };              
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {             
        var binding = valueAccessor();
        if (binding.firstTime) {
            binding.firstTime = false;
            return;
        }               

        $(element).children().remove(); 
        ko.applyBindingsToNode(element, { template: { name: binding.template, foreach: binding.value }}, viewModel)
    }
};      

これにより、各要素に特定のバインディングが適用され、最初の更新時にコンテンツが通常の foreach バインディングに置き換えられます。このアプローチは、依然として 2 つのテンプレートが必要であることを意味します。これらは両方とも、サーバーによってレンダリングされる JSON を介して状態を初期化することも伴います。

私が選択した現在のアプローチ (まだ変更される可能性があります) は、すべての Knockout テンプレートをスクリプト タグ内に配置して、NoJS ブラウザーでレンダリングされないようにすることです。NoJS テンプレートは、サーバー側で div のコンテンツとしてレンダリングされます。Knockout テンプレートがレンダリングされるとすぐに、div の内容がスクリプト タグ内の Knockout テンプレートに置き換えられます。それらを同一/類似の方法でスタイルして、移行をシームレスにすることができます。これが不可能な場合は、CSS を使用して noJS テンプレートを非表示にします。

最終的に、Knockout.js とプログレッシブ エンハンスメントは実際にはうまく連携しないという結論に達しました。どちらか一方を選択する必要があります。つまり、プログレッシブ エンハンスメントを必要とするアプリケーションの一部を直接 jQuery などの従来の方法を使用して構築する必要があります。 DOM 操作。

于 2012-01-28T13:29:46.523 に答える
3

data-サーバー側のテンプレートにさまざまな属性を追加するだけです。JavaScriptを無効にしても問題はないので、JavaScriptを使用しても問題はありません。

于 2012-01-22T12:35:35.873 に答える
3

それを行うきれいな方法はないと思います。個人的には、バックエンドでページをレンダリングし、まったく同じコンテキスト データ (JSON としてシリアル化) をフロントエンドに渡し、それを使用して Knockout をセットアップします。これは、いくつかの重複があることを意味します。おそらく、バックエンドを node.js に切り替えると、ここでの作業が簡素化されるでしょう。

于 2012-01-22T13:45:11.173 に答える
0

プログレッシブ エンハンスメントは、フォームのような非ループ データを使用するとはるかに簡単になります (ここで書いたように: http://www.tysoncadenhead.com/blog/using-knockout-for-progressive-enhancement )。個人的には、DOM 内の複数のアイテムをループして再レンダリングするのは、実装が難しいように思えますが、これ以上良いものは思いつきません。

于 2014-07-23T18:33:20.527 に答える