【问题标题】:DOM element inside backbone template doesn't respond to event主干模板内的 DOM 元素不响应事件
【发布时间】:2014-12-12 17:44:29
【问题描述】:

我有 2 个主干视图。一个视图 (AppView) 代表整个集合,当它获取它时,它会解析集合并为集合中的每个模型生成单独的模型视图。

我遇到的一个问题是创建模型视图时,它们不再响应我的 click 事件,这是模型视图的一种方法。在模型视图中,如果我将 tagName 替换为 el,则可以触发该事件,但它会为集合中的每个模型而不是单个模型触发。

我认为这与加载时从模板中解开的事件有关,但我不知道如何在不解开它们的情况下重新绑定或生成模板。

// INDIVIDUAL ITEMS WITHIN THE VIEW
ModelView = Backbone.View.extend({
// el: '#item-block', // click event shows an action for all 20 models within the collection
tagName: '.item-wrapper', // click event not heard
template: _.template($('#template').html()),
events: {
    'click.details': 'fireModel', // .details is a div inside of the template
},
initialize: function () {

    // _.bindAll(this, 'render', 'fireModel');
    this.render();

},
render: function() {

    var holder   = $('#item-block');

    if(this.model.attributes.caption == null) {
        var cloned = _.clone(this.model.get('caption'));

        cloned = {};
        cloned.text = '';

        this.model.set('caption', cloned);
    }

    holder.append(this.template(this.model.toJSON()));

    // this.delegateEvents()

    // return this;

},
fireModel: function(e) {

    console.log('clicked');

},
});


// COLLECTION GENERATES INDIVIDUAL MODEL VIEW
AppView = Backbone.View.extend({
el: '#social',
events: {
    'click #load-more': 'fetchCollection'
},
initialize: function() {
    this.collection = new MyCollection();

    this.collection.on('sync', this.render, this);

    this.collection.fetchData();
},
render: function() {

    for (var i = 0; i < this.collection.cache.models.length; i ++) {
        modelView = new ModelView({model: this.collection.cache.models[i]});
    }

},
fetchCollection: function() {
    this.collection.fetchData();
},

});

// CREATE NEW COLLECTION
app = new AppView

这是模板

<section id="social">

<div id="item-block">   
</div>

<div id="load-more">Load More</div>

</section>

<script type="text/template" id="template">

<div class="item-wrapper">
    <div class="details">
        <span class="caption"><%= caption.text %></span>
    </div>
    <div class="image">
        <img src="<%= images.standard_resolution.url %>" data-id="<%= id %>">
    </div>
</div>

</script>

<!-- JS LIBS AND BACKBONE SCRIPTS HERE -->

【问题讨论】:

  • 你也可以添加模板文件(HTML)吗?
  • 好的,我更新了帖子
  • 你不应该说'click .details'而不是'click.details'吗?为什么要克隆标题,然后立即为克隆分配一个空对象?
  • Caption 作为 null 或嵌套对象返回。如果我修改嵌套对象,Backbone 无法识别发生的更改,但我找到了一个建议使用克隆作为解决方法的教程(下面的链接)。它是一个空对象,所以我可以将它作为caption.text 放入模板中,否则它将是caption(空)和caption.text(里面的东西)。 click .details 和 click.details 的功能相同。 crittercism.com/blog/nested-attributes-in-backbone-js-models

标签: javascript backbone.js


【解决方案1】:

需要注意的几点:

首先,我要提一下Backbone.View的tagName属性应该是HTML元素的名称(div,ul,....,默认是div)。

第二,您将模型视图(子视图)从模型视图附加到 appView。它可以更好地实施 方式。将该逻辑移至 appView (parentView)。

第三,使用 Underscore.js 的 each 方法而不是 for 循环。

使用documentFragment缓存childViews,一次性追加,而不是一一追加(性能优化)。

最后的样子应该是:

ModelView = Backbone.View.extend({
    template: _.template($('#template').html()),
    attributes: {
       'class': 'item-wrapper'
    },
    events: {
        'click .details': 'fireModel', // .details is a div inside of the template
    },
    initialize: function () {
        this.render();
    },
    render: function() {
        this.$el.html(this.template(this.model.toJSON()));
        return this;
    },
    fireModel: function(e) {
        console.log('clicked');
    },
});


// COLLECTION GENERATES INDIVIDUAL MODEL VIEW
AppView = Backbone.View.extend({
el: '#social',
events: {
    'click #load-more': 'fetchCollection'
},
initialize: function() {
    this.collection = new MyCollection();
    this.collection.on('sync', this.render, this);
    this.collection.fetchData();
},
render: function() {
    var buffer = document.createDocumentFragment();
    this.collection.each(function(model){
        if(model.attributes.caption == null) {
            // do your checks here
        } 
        var itemView = new ModelView({model: model});
        buffer.appendChild(itemView.render().el); // adding it to buffer   
    });

    this.$el.append(buffer); // appending all at once
}
});

// CREATE NEW COLLECTION
app = new AppView();

更新

这样,任何时候集合的sync 事件被触发,它都会将新的 itemViews 附加到 parentView,所以一定要在那里添加检查。

【讨论】:

  • 成功了,谢谢!!关于 DocumentFragment 的好注释。您可能想要更新底部,因为 this.buffer 应该被称为 buffer 然而
  • @user2989731 如果回答对您有帮助并解决了您的问题,您可以接受。
【解决方案2】:

也许你应该在事件和选择器之间插入一些空格。

试试

'click .details': 'fireModel'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-12
    • 1970-01-01
    • 2014-11-10
    相关资源
    最近更新 更多