2

モデルとビューがあります。ビューにはモデルの属性が表示され、ユーザーはこれらの属性を操作できます。問題は、属性が変更されると、ビュー全体が再レンダリングされ、多くの問題が発生することです。

テキスト入力の例のぼかしイベントは、新しい入力を属性に保存し、レンダリングを開始します。つまり、ユーザーがそのテキスト入力から同じビューのボタンに直接クリックした場合、最初に発生したイベントがぼやけてビュー全体が再レンダリングされ、ボタン クリック イベントが失われるため、そのイベントは決して発生しません。

私には2つのアイデアがあります:

  1. すべての属性が個別のテンプレートにある単一のビューを用意します。次に、特定の属性変更イベントにバインドし、レンダリングで、変更された属性の html のみを更新します。ビューに変更された属性のみを強制的に更新させるには多くの作業があるため、これはハックのようです。それは、すでに複雑なビューに多くの不必要な複雑さを追加します。
  2. それぞれがモデルの属性を表すビューで構成されるマスター ビューを作成します。これにより、多くのビューが作成されますが、機能はほとんどありません。

私は 2. オプションを好むようです。どう思いますか?ベストプラクティスは何ですか? これを処理するより良い方法はありますか?

4

2 に答える 2

1

これはとても簡単にできると思います。

一歩下がって、イベントをどこでバインドしているかを考えてください。親デリゲートを使用するのではなく、個々の要素の上に直接バインドしているようです。

これが例です

Backbone.View.extend({
  el: $("div.parent"),
  events: function() {
    this.$el.on("click", "input[type=button]", function(){});
    // jquery cross browser on this
    this.$el.on("blur", "input[type=text]", function(){});
  },
  initialize: function() {
    this.model.bind("change", this.render, this);
  },
  render: function() {
    this.$el.html('<input type="text" /><input type="button" />');
  }
});

エルとその構造は次のようになります

<div class="parent">
  <input type="text" />
  <input type="button" />
</div>

したがって、this。$elはdiv.parentを指します。this。$elの内容を常に再レンダリングできます。また、html構造が変更されない限り、イベントがバインド解除されることを心配する必要はありません。もう1つの解決策は、本当に委任を実行できない場合は、再度レンダリングするたびにeventsメソッドを呼び出すだけです。

于 2013-01-10T09:16:51.963 に答える
1

あなたが自分で言ったように、あなたのオプションは両方とも非常に複雑に見えます。しかし、場合によっては、さらに複雑になることが必要悪になることもあります。ただし、更新されたフィールドが比較的単純なもの (値を要素または入力フィールドにバインドするなど) である場合は、追加のビュー/テンプレートの抽象化を作成せずに DOM 要素を更新するだけです。

モデルがあるとします:

var person = new Person({ firstName: 'John', lastName: 'Lennon', instrument:'Guitar' });

そして、次のテンプレートをレンダリングするビュー:

<div>First Name: <span class="firstName">{{firstName}}</span></div>
<div>Last Name: <span class="lastName">{{lastName}}</span></div>
<div>Instrument: <input class="instrument" value="{{instrument}}"></input></div>

どのプロパティ変更がどの要素を更新するかをビューで宣言し、モデルchangeイベントをそれらを更新する関数にバインドできます。

var PersonView = Backbone.View.extend({

  //convention: propertyName+"Changed"
  //specify handler as map of selector->method or a function.
  firstNameChanged:  { '.firstName': 'text' },
  lastNameChanged:   { '.lastName': 'text' },
  instrumentChanged: { '.instrument': 'val' },
  otherFieldChanged: function(val) { //do something else },

  initialize: function (opts) {
    this.model.on('change', this.update, this);
  },

  //called when change event is fired
  update: function(state) {
    _.each(state.changed, function(val, key) {
      var handler = this[key + "Changed"];
      //handler specified for property?
      if(handler) {
        //if its a function execute it
        if(_.isFunction(handler)) {
          handler(val);
        //if its an object assume it's a selector->method map
        } else if(_.isObject(handler)) {
          _.each(handler, function(prop, selector) {
            this.$(selector)[prop](val);
          }, this);              
        }
      }
    }, this);
  }

クラス化された要素を DOM に追加し、それらをビュー コードで維持する必要があるため、このようなソリューションは非常に複雑なビューには対応できません。しかし、より単純なケースでは、これは非常にうまくいくかもしれません。

さらに、ビューが自然にセクションに分割される場合は、複数の小さなビューのビューを構成することを試みることは常に良いことです。そうすれば、単一のフィールドを個別に更新する必要がなくなります。

于 2013-01-10T09:22:27.843 に答える