在Backbone.js视图中动态设置id和className

Nad*_*dav 85 javascript backbone.js

我正在学习和使用Backbone.js.

我有一个Item模型和一个相应的Item视图.每个模型实例都有item_class和item_id属性,我希望将它们反映为相应视图的"id"和"class"属性.实现这一目标的正确方法是什么?

例:

var ItemModel = Backbone.Model.extend({      
});

var item1 = new ItemModel({item_class: "nice", item_id: "id1"});
var item2 = new ItemModel({item_class: "sad", item_id: "id2"});

var ItemView = Backbone.View.extend({       
});
Run Code Online (Sandbox Code Playgroud)

我应该如何实现视图,以便视图的el将转换为:

<div id="id1" class="nice"></div>
<div id="id2" class="sad"> </div>
Run Code Online (Sandbox Code Playgroud)

在我看到的大多数示例中,视图的el用作无意义的包装元素,在其中必须手动编写"语义"代码.

var ItemView = Backbone.View.extend({
   tagName:  "div",   // I know it's the default...

   render: function() {
     $(this.el).html("<div id="id1" class="nice"> Some stuff </div>");
   }       
});
Run Code Online (Sandbox Code Playgroud)

所以当渲染时,一个人得到

<div> <!-- el wrapper -->
    <div id="id1" class="nice"> Some stuff </div>
</div>
Run Code Online (Sandbox Code Playgroud)

但这似乎是浪费 - 为什么有外部div?我想让el直接翻译成内部div!

JMM*_*JMM 132

摘要:使用模型数据动态设置视图属性

http://jsfiddle.net/5wd0ma8b/

// View class with `attributes` method
var View = Backbone.View.extend( {
  attributes : function () {
    // Return model data
    return {
      class : this.model.get( 'item_class' ),
      id : this.model.get( 'item_id' )
    };
  }
  // attributes
} );

// Pass model to view constructor
var item = new View( {
  model : new Backbone.Model( {
    item_class : "nice",
    item_id : "id1"
  } )
} );
Run Code Online (Sandbox Code Playgroud)
  • 此示例假定您允许Backbone为您生成DOM元素.

  • attributes在设置传递给视图构造函数的属性(在本例中为model)之后调用该方法,允许您在Backbone创建之前使用模型数据动态设置属性el.

  • 与其他一些答案相反:不对视图类中的属性值进行硬编码,从模型数据中动态设置它们; 不要等到render()设定attr vals; 每次通话都不会重复设定attr vals render(); 不必要地在DOM元素上手动设置attr vals.

  • 请注意,如果在调用Backbone.View.extend或视图构造函数(例如new Backbone.View)时设置类,则必须使用DOM属性名称className,但如果通过attributeshash /方法设置它(如本例所示),则必须使用属性名称class.

  • 截至Backbone 0.9.9:

    在声明查看...... el,tagName,id并且className现在可以,如果你想在运行时确定它们的值定义为功能.

    我提到这种情况,以防有可能作为使用attributes所示方法的替代方案.

使用现有元素

如果您正在使用现有元素(例如传递el给视图构造函数)......

var item = new View( { el : some_el } );
Run Code Online (Sandbox Code Playgroud)

...然后attributes不会应用于元素.如果尚未在元素上设置所需的属性,或者您不想在视图类和其他位置复制该数据,则可能需要向initialize适用attributes于您的视图构造函数添加方法el.像这样(使用jQuery.attr):

View.prototype.initialize = function ( options ) {
  this.$el.attr( _.result( this, 'attributes' ) );
};
Run Code Online (Sandbox Code Playgroud)

使用el,渲染,避免包装

在我看到的大多数示例中,视图的el用作无意义的包装元素,在其中必须手动编写"语义"代码.

没有理由view.el需要成为"无意义的包装元素".实际上,这通常会打破DOM结构.<li>例如,如果视图类表示一个元素,则需要将其呈现为<li>- 将其呈现为一个<div>或任何其他元素将破坏内容模型.你可能会希望把重点放在如何正确设置视图的元素(使用类似的属性tagName,classNameid),然后渲染它的内容之后.

如何让Backbone视图对象与DOM交互的选项是开放的.有两个基本的初始场景:

  • 您可以将现有DOM元素附加到Backbone视图.

  • 您可以允许Backbone创建一个与文档断开连接的新元素,然后以某种方式将其插入到文档中.

您可以通过多种方式为元素生成内容(设置文字字符串,如示例中所示;使用模拟库,如Mustache,Handlebars等).你应该如何使用el视图的属性取决于你正在做什么.

现有元素

您的渲染示例表明您具有要分配给视图的现有元素,尽管您没有显示视图的实例化.如果是这种情况,并且该元素已经在文档中,那么您可能想要做这样的事情(更新内容el,但不要改变el自己):

render : function () {
  this.$el.html( "Some stuff" );
}
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/vQMa2/1/

生成的元素

假设您没有现有元素,并允许Backbone为您生成一个元素.您可能想要做这样的事情(但是建立事物可能更好,以便您的视图不负责了解自身之外的任何事情):

render : function () {
  this.$el.html( "Some stuff" );
  $( "#some-container" ).append( this.el );
}
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/vQMa2/

模板

就我而言,我正在使用模板,例如:

<div class="player" id="{{id}}">
<input name="name" value="{{name}}" />
<input name="score" value="{{score}}" />
</div>
<!-- .player -->
Run Code Online (Sandbox Code Playgroud)

模板表示完整视图.换句话说,模板周围没有包装器 - div.player将是我视图的根或最外层元素.

我的播放器类看起来像这样(非常简化的示例render()):

Backbone.View.extend( {
  tagName : 'div',
  className : 'player',

  attributes : function () {
    return {
      id : "player-" + this.model.cid
    };
  },
  // attributes

  render : function {
    var rendered_template = $( ... );

    // Note that since the top level element in my template (and therefore
    // in `rendered_template`) represents the same element as `this.el`, I'm
    // extracting the content of `rendered_template`'s top level element and
    // replacing the content of `this.el` with that.
    this.$el.empty().append( rendered_template.children() );
  }      
} );
Run Code Online (Sandbox Code Playgroud)

  • @Kel没错这就是实现动态的东西像什么问题问的,填充与模型数据的属性,而无需使用重复的代码,其中的意见被实例化的好办法.你可能知道这一点,但是为了防止它不明显,Backbone的一个特性是你可以使用一个函数来返回一个散列作为`attributes`的值,就像许多其他可以作为函数提供的Backbone属性一样或其他一些类型的价值.在这些情况下,Backbone会检查值是否为函数,调用它并使用返回值. (2认同)

Dan*_*oke 95

在你看来,做这样的事情

var ItemView = Backbone.View.extend({
   tagName:  "div",   // I know it's the default...

   render: function() {
     $(this.el).attr('id', 'id1').addClass('nice').html('Some Stuff'); 
   }       
});
Run Code Online (Sandbox Code Playgroud)

  • 这个答案没有演示基于模型数据动态设置视图属性,它只是显示了对属性值进行硬编码的替代方法. (13认同)
  • @Clint,我不会指望OP显而易见."他的示例代码也没有使用模型数据." - 那是因为他不知道如何,因此他寻求帮助的原因.我似乎很清楚,他正在询问如何使用模型数据*设置view.el*的attrs,并且不知道如何去做.答案甚至没有说明如何做到这一点,为什么你会等到渲染完成它,或者每次渲染时再做一次?"这个答案有效......" - 它是如何运作的?每个创建的视图都具有相同的attr vals.它唯一展示的是如何避免包装. (5认同)
  • @JMM - 他的示例代码也没有使用模型数据.这个答案基于他的示例代码.显然,模型数据可以代替值. (3认同)
  • @JMM - 点了.向上投票你的答案:-) (2认同)

Jør*_*gen 27

您可以设置属性classNameid根元素: http://documentcloud.github.com/backbone/#View-extend

var ItemView = Backbone.View.extend({
   tagName:  "div",   // I know it's the default...
   className : 'nice',
   id : 'id1',
   render: function() {
     $(this.el).html("Some stuff");
   }       
});
Run Code Online (Sandbox Code Playgroud)

编辑包含基于构造函数参数设置id的示例

如果视图的构造如上所述:

var item1 = new ItemModel({item_class: "nice", item_id: "id1"});
var item2 = new ItemModel({item_class: "sad", item_id: "id2"});
Run Code Online (Sandbox Code Playgroud)

然后可以这样设置值:

// ...
className: function(){
    return this.options.item_class;
},
id: function(){
    return this.options.item_id;
}
// ...
Run Code Online (Sandbox Code Playgroud)

  • 我不觉得这个答案是正确的,因为每个`ItemView`都会有`id:'id1'.这必须基于`model.id`在执行时间**中计算**. (3认同)

Mar*_*cus 6

我知道这是一个老问题,但增加了参考.在新的骨干版本中,这似乎更容易.在Backbone 1.1中,id和className属性在函数中使用下划线来计算ensureElement(参见源代码),_.result如果className或者id是函数,它将被调用,否则将使用它的值.

所以你可以直接在构造函数中给出className,给出另一个将在className中使用的参数等等.很多选项

所以这应该工作

var item1 = new ItemModel({item_class: "nice", item_id: "id1"});
var item2 = new ItemModel({item_class: "sad", item_id: "id2"});

var ItemView = Backbone.View.extend({       
  id: function() { return this.model.get('item_id'); },
  className: function() { return this.model.get('item_class'); }
});
Run Code Online (Sandbox Code Playgroud)