การตั้งค่า id และ className แบบไดนามิกในมุมมอง Backbone.js


85

ฉันอยู่ระหว่างการเรียนรู้และใช้งาน Backbone.js

ฉันมีโมเดลรายการและมุมมองรายการที่เกี่ยวข้อง อินสแตนซ์โมเดลแต่ละรายการมีแอตทริบิวต์ 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({       
});

ฉันควรใช้มุมมองอย่างไรเพื่อให้มุมมองของเอลแปลเป็น:

<div id="id1" class="nice"></div>
<div id="id2" class="sad"> </div>

ในตัวอย่างส่วนใหญ่ที่ฉันได้เห็นelของมุมมองทำหน้าที่เป็นองค์ประกอบของ wrapper ที่ไม่มีความหมายซึ่งต้องเขียนโค้ด 'ความหมาย' ด้วยตนเอง

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>");
   }       
});

ดังนั้นเมื่อแสดงผลหนึ่งจะได้รับ

<div> <!-- el wrapper -->
    <div id="id1" class="nice"> Some stuff </div>
</div>

แต่ดูเหมือนจะเสียเปล่า - ทำไมต้องมี div ภายนอก? ฉันต้องการให้เอลแปลเป็น div ภายในโดยตรง!

คำตอบ:


133

สรุป: ตั้งค่าแอ็ตทริบิวต์มุมมองแบบไดนามิกด้วยข้อมูลโมเดล

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"
  } )
} );
  • ตัวอย่างนี้สมมติว่าคุณอนุญาตให้ Backbone สร้างองค์ประกอบ DOM ให้คุณ

  • attributesวิธีการที่เรียกว่าหลังจากคุณสมบัติส่งผ่านไปยังตัวสร้างมุมมองที่มีการตั้งค่า (ในกรณีนี้model) elที่ช่วยให้คุณสามารถตั้งค่าแบบไดนามิกคุณลักษณะที่มีข้อมูลรูปแบบก่อนที่จะสร้างโครง

  • ตรงกันข้ามกับคำตอบอื่น ๆ : ไม่ใช้ค่าแอตทริบิวต์ฮาร์ดโค้ดในคลาสมุมมองตั้งค่าแบบไดนามิกจากข้อมูลโมเดล ไม่รอจนกว่าrender()จะตั้งค่า attr vals; ไม่ได้ตั้งค่าซ้ำ ๆ attr Vals ในการเรียกร้องให้ทุกคนrender(); ไม่ได้ตั้งค่า attr vals บนองค์ประกอบ DOM ด้วยตนเองโดยไม่จำเป็น

  • โปรดทราบว่าหากตั้งค่าคลาสเมื่อเรียกBackbone.View.extendหรือตัวสร้างมุมมอง (เช่นnew Backbone.View) คุณต้องใช้ชื่อคุณสมบัติ DOM classNameแต่ถ้าตั้งค่าผ่านattributesแฮช / วิธีการ (ดังตัวอย่างนี้) คุณต้องใช้ชื่อแอตทริบิวต์, class.

  • ณ Backbone 0.9.9:

    เมื่อประกาศ View ... el, tagName, idและclassNameตอนนี้อาจจะกำหนดเป็นฟังก์ชั่นถ้าคุณต้องการค่าของพวกเขาที่จะได้รับการพิจารณาที่รันไทม์

    ฉันพูดถึงเรื่องนี้ในกรณีที่มีสถานการณ์ที่จะเป็นประโยชน์เป็นทางเลือกในการใช้attributesวิธีการตามภาพประกอบ

ใช้องค์ประกอบที่มีอยู่

หากคุณใช้องค์ประกอบที่มีอยู่ (เช่นส่งผ่านelไปยังตัวสร้างมุมมอง) ...

var item = new View( { el : some_el } );

... จากนั้นattributesจะไม่ถูกนำไปใช้กับองค์ประกอบ หากคุณลักษณะที่ต้องการไม่ได้ตั้งอยู่บนองค์ประกอบหรือคุณไม่ต้องการที่จะทำซ้ำข้อมูลนั้นในระดับมุมมองของคุณและสถานที่อื่นแล้วคุณอาจต้องการที่จะเพิ่มinitializeวิธีการเพื่อให้ตัวสร้างมุมมองของคุณที่ใช้ในการattributes elสิ่งนี้ (ใช้jQuery.attr):

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

การใช้งานการelแสดงผลการหลีกเลี่ยงกระดาษห่อหุ้ม

ในตัวอย่างส่วนใหญ่ที่ฉันได้เห็น el ของมุมมองทำหน้าที่เป็นองค์ประกอบของ wrapper ที่ไม่มีความหมายซึ่งต้องเขียนโค้ด 'ความหมาย' ด้วยตนเอง

ไม่มีเหตุผลที่view.elจะต้องเป็น "องค์ประกอบเสื้อคลุมที่ไร้ความหมาย" ในความเป็นจริงสิ่งนี้มักจะทำลายโครงสร้าง DOM หากคลาสมุมมองเป็นตัวแทนของ<li>องค์ประกอบตัวอย่างเช่นจำเป็นต้องแสดงผลเป็น<li>- การแสดงผลเป็น<div>องค์ประกอบหรือองค์ประกอบอื่นใดจะทำให้โมเดลเนื้อหาเสียหาย คุณอาจจะต้องการที่จะมุ่งเน้นไปที่การตั้งค่าได้อย่างถูกต้ององค์ประกอบมุมมองของคุณ (โดยใช้คุณสมบัติเช่นtagName, classNameและid) และจากนั้นการแสดงผลของเนื้อหานั้นไม่นาน

ตัวเลือกสำหรับวิธีทำให้วัตถุมุมมอง Backbone ของคุณโต้ตอบกับ DOM นั้นเปิดกว้าง สถานการณ์เริ่มต้นพื้นฐานมี 2 สถานการณ์:

  • คุณสามารถแนบองค์ประกอบ DOM ที่มีอยู่เข้ากับมุมมอง Backbone

  • คุณสามารถอนุญาตให้ Backbone สร้างองค์ประกอบใหม่ที่ไม่ได้เชื่อมต่อกับเอกสารจากนั้นจึงแทรกลงในเอกสาร

มีหลายวิธีที่คุณสามารถสร้างเนื้อหาสำหรับองค์ประกอบได้ (ตั้งค่าสตริงตามตัวอักษรตามตัวอย่างของคุณใช้ไลบรารีเทมเพลตเช่นหนวดแฮนด์บาร์ ฯลฯ ) คุณควรใช้ไฟล์elคุณสมบัติของมุมมองอย่างไรขึ้นอยู่กับสิ่งที่คุณทำ

องค์ประกอบที่มีอยู่

ตัวอย่างการแสดงผลของคุณแสดงให้เห็นว่าคุณมีองค์ประกอบที่คุณกำหนดให้กับมุมมองอยู่แล้วแม้ว่าคุณจะไม่แสดงการสร้างอินสแตนซ์ของมุมมองก็ตาม หากเป็นกรณีนี้และองค์ประกอบนั้นอยู่ในเอกสารแล้วคุณอาจต้องการทำสิ่งนี้ (อัปเดตเนื้อหาelแต่อย่าแก้ไขelเอง):

render : function () {
  this.$el.html( "Some stuff" );
}

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

องค์ประกอบที่สร้างขึ้น

สมมติว่าคุณไม่มีองค์ประกอบที่มีอยู่และคุณอนุญาตให้ Backbone สร้างขึ้นมาให้คุณ คุณอาจต้องการทำบางสิ่งเช่นนี้ (แต่น่าจะดีกว่าที่จะออกแบบสิ่งต่าง ๆ เพื่อให้มุมมองของคุณไม่รับผิดชอบต่อการรับรู้สิ่งที่อยู่ภายนอกตัวมันเอง):

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

http://jsfiddle.net/vQMa2/

เทมเพลต

ในกรณีของฉันฉันกำลังใช้เทมเพลตเช่น:

<div class="player" id="{{id}}">
<input name="name" value="{{name}}" />
<input name="score" value="{{score}}" />
</div>
<!-- .player -->

เทมเพลตแสดงถึงมุมมองที่สมบูรณ์ กล่าวอีกนัยหนึ่งคือจะไม่มีกระดาษห่อหุ้มรอบเทมเพลต -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() );
  }      
} );

วิธีที่ยอดเยี่ยมในการเขียนทับคุณสมบัติแอตทริบิวต์ด้วยฟังก์ชันและส่งคืนวัตถุอีกครั้ง!
Kel

2
@Kel ใช่เป็นวิธีที่ดีในการทำบางสิ่งให้สำเร็จแบบไดนามิกเช่นคำถามที่ถามโดยเติมข้อมูลแอตทริบิวต์ด้วยข้อมูลแบบจำลองโดยไม่ต้องใช้รหัสซ้ำที่มุมมองถูกสร้างอินสแตนซ์ คุณอาจรู้สิ่งนี้ แต่ในกรณีที่ไม่ชัดเจนมันเป็นคุณสมบัติของ Backbone ที่คุณสามารถใช้ฟังก์ชันที่ส่งคืนแฮชเป็นค่าattributesเช่นคุณสมบัติ Backbone อื่น ๆ ที่สามารถนำมาใช้เป็นฟังก์ชันหรืออื่น ๆ ประเภทของค่า ในกรณีเหล่านั้น Backbone จะตรวจสอบว่าค่าเป็นฟังก์ชันหรือไม่เรียกใช้และใช้ค่าที่ส่งคืน
JMM

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'); 
   }       
});

นี่คือคำตอบที่ถูกต้องสำหรับคำถามนี้และควรยอมรับ
reach4thelasers

13
คำตอบนี้ไม่ได้แสดงให้เห็นถึงการตั้งค่าแอตทริบิวต์มุมมองแบบไดนามิกตามข้อมูลแบบจำลอง แต่จะแสดงวิธีอื่นในการเข้ารหัสค่าแอตทริบิวต์
JMM

3
@JMM - โค้ดตัวอย่างของเขาไม่ได้ใช้ข้อมูลโมเดลเช่นกัน คำตอบนี้ทำงานโดยอาศัยโค้ดตัวอย่างของเขา เห็นได้ชัดว่าข้อมูลแบบจำลองสามารถใช้แทนค่าได้
Clint

5
@ คลินต์ฉันจะไม่นับว่าสิ่งนั้นชัดเจนสำหรับ OP "โค้ดตัวอย่างของเขาไม่ได้ใช้ข้อมูลโมเดลเช่นกัน" - นั่นเป็นเพราะเขาไม่รู้วิธีและด้วยเหตุนี้เขาจึงขอความช่วยเหลือ ดูเหมือนชัดเจนสำหรับฉันว่าเขาถามถึงวิธีตั้งค่ามุมมอง el โดยใช้ข้อมูลโมเดลและไม่รู้ว่าจะทำอย่างไร คำตอบไม่ได้แสดงวิธีการทำเช่นนั้นแล้วทำไมคุณถึงต้องรอจนกว่าจะแสดงผลหรือทำใหม่ทุกครั้งที่แสดงผล? "คำตอบนี้ได้ผล ... " - ทำงานอย่างไร? ทุกมุมมองที่สร้างขึ้นแบบนั้นจะมีค่า attr vals เดียวกัน สิ่งเดียวที่แสดงคือวิธีหลีกเลี่ยงกระดาษห่อหุ้ม
JMM

OP หมดไปตั้งแต่ ก.พ. 55 :( นี่คือ +1 อีกครั้งสำหรับคำตอบนี้
Almo

27

คุณสามารถตั้งค่าคุณสมบัติclassNameและidบนองค์ประกอบรูท: 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");
   }       
});

แก้ไขรวมตัวอย่างของการตั้งค่า id ตามพารามิเตอร์ตัวสร้าง

หากมุมมองถูกสร้างขึ้นตามที่กล่าวไว้:

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

จากนั้นสามารถกำหนดค่าด้วยวิธีนี้:

// ...
className: function(){
    return this.options.item_class;
},
id: function(){
    return this.options.item_id;
}
// ...

3
ผมไม่รู้สึกว่าคำตอบนี้ถูกต้องแล้วเพราะทุกคนจะมีItemView id: 'id1'สิ่งนี้จะต้องคำนวณในเวลาดำเนินการตามในmodel.id.
fguillen

แน่นอนคุณสามารถตั้งค่า ID ได้ตามที่คุณต้องการ ใช้ฟังก์ชันตัวแปรหรืออะไรก็ได้ รหัสของฉันมีเพียงตัวอย่างซึ่งชี้ให้เห็นถึงวิธีการตั้งค่าในองค์ประกอบราก
Jørgen

ฉันได้เพิ่มตัวอย่างการล้างวิธีการตั้งค่าแบบไดนามิกตามพารามิเตอร์ตัวสร้าง
Jørgen

นี่คือคำตอบที่ถูกต้อง ใช้คุณสมบัติ Backbone อย่างถูกต้องในการแก้ปัญหา
Marc-Antoine Lemieux

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'); }
});

ตัวอย่างของคุณไม่ถูกต้องคุณต้องการid: function() { return this.model.get('item_id'); })
Cobby

4

ตัวอย่างอื่น ๆ ไม่ได้แสดงวิธีการดึงข้อมูลจากแบบจำลองจริงๆ ในการเพิ่ม id และคลาสแบบไดนามิกจากข้อมูลของโมเดล:

var ItemView = Backbone.View.extend({
   tagName:  "div",

   render: function() {
     this.id = this.model.get('item_id');
     this.class = this.model.get('item_class');
     $(this.el).attr('id',this.id).addClass(this.class).html('Some Stuff'); 
   }       
});

นั่นคือ 'this.className' หรือ 'this.class'?
Gabe Rainbow

2

คุณต้องลบ tagName และประกาศ el

'tagName' หมายความว่าคุณต้องการให้กระดูกสันหลังสร้างองค์ประกอบ หากองค์ประกอบมีอยู่แล้วใน DOM คุณสามารถระบุเอลเช่น:

el: $('#emotions'),

และหลังจากนั้น:

render: function() { 
     $(this.el).append(this.model.toJSON());
}

2

พยายามกำหนดค่าในวิธีการเริ่มต้นซึ่งจะกำหนด id และคลาสให้กับแอตทริบิวต์ div แบบไดนามิก

var ItemView = Backbone.View.extend( {
    tagName : "div",   
    id      : '',
    class   : '',

    initialize : function( options ) {
        if ( ! _.isUndefined( options ) ) {
            this.id = options.item_id;
            this.class= options.item_class;
        }
    },

    render : function() {
        $( this.el ).html( this.template( "stuff goes here" ) ); 
    }
} );

@Michel Pleasae อ่านเอกสารนี้backbonejs.org/#View-constructor
Hemanth

0

นี่เป็นวิธีง่ายๆในการเปลี่ยนคลาสขององค์ประกอบของมุมมองแบบไดนามิกผ่านโมเดลและอัปเดตเมื่อมีการเปลี่ยนแปลงโมเดล

var VMenuTabItem = Backbone.View.extend({
    tagName: 'li',
    events: {
        'click': 'onClick'
    },
    initialize: function(options) {

        // auto render on change of the class. 
        // Useful if parent view changes this model (e.g. via a collection)
        this.listenTo(this.model, 'change:active', this.render);

    },
    render: function() {

        // toggle a class only if the attribute is set.
        this.$el.toggleClass('active', Boolean(this.model.get('active')));
        this.$el.toggleClass('empty', Boolean(this.model.get('empty')));

        return this;
    },
    onClicked: function(e) {
        if (!this.model.get('empty')) {

            // optional: notify our parents of the click
            this.model.trigger('tab:click', this.model);

            // then update the model, which triggers a render.
            this.model.set({ active: true });
        }
    }
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.