【问题标题】:Howto bind a click event in a Backbone subview如何在 Backbone 子视图中绑定点击事件
【发布时间】:2012-11-07 11:43:20
【问题描述】:

我在理解 Backbone 子视图中的事件绑定时遇到问题。我的观点定义如下:

TenantView = Backbone.View.extend({
  events: {
    "click": "setActive"
  },
  initialize: function() {
    this.parentEl = this.options.parentEl;
    return this.render();
  },
  template: new EJS({
    url: '/scripts/templates/tenant.ejs'
  }),
  render: function() {
    $(this.parentEl).children('ul').append(this.template.render(this.model));
    return this;
  },
  setActive: function(event) {
    return this.model.set('active', true);
  }
});

模板只包含一个li,其中包含一个a。这样做,我的视图上的点击事件不会被捕获,我的方法setActive 永远不会被触发。

当我通过el 之类的el: 'li' 属性扩展我的视图时,我的(2) 个视图之一正常运行并触发setActive 函数。第二种观点根本没有反应。如果我在视图初始化期间检查el 属性,则工作视图的el 属性指向右侧li,失败的视图el 指向可以在页面中找到的第一个li

正如你所看到的,当谈到 el 属性的含义时,我完全迷失了。

问题是,如何将点击视图绑定到这个视图setActive 函数?

谁能赐教?

问候 费利克斯

【问题讨论】:

    标签: javascript events backbone.js


    【解决方案1】:

    首先,您可以阅读documentationthis。那里给出了关于el的解释。

    由于TenantView 具有parentEl 属性,我假设它是从一些parent_view 呈现的。我会建议一些类似下面的方法并试一试。

    var ChildView = Backbone.View.extend({
      tagName : "li", // change it according to your needs
    
      events : {
        "click": "setActive"
      },
    
      initialize : function() {
        _.bindAll(this, "setActive");
        // code to initialize child_view
      },
    
      render : function() {
        // as I'm not familiar with the way you are using template, 
        // I've put simple call to render template, but it should render the
        // content to be kept inside "li" tag
        this.$el.html(this.template()); 
    
        return this;
      },
    
      setActive : function(event) {
        // code to be executed in event callback
      }
    });
    
    
    var ParentView = Backbone.View.extend({
      el : "#parent_view_el",
    
      initialize : function() {
        // parent view initialization code
      },
    
      render : function() {
        // a place from where ChildView is initialized
        // might be a loop through collection to initialize more than one child views
        // passing individual model to the view
    
        var child_view = new ChildView();
    
        this.$("ul").append(child_view.render().$el); // equivalent to this.$el.find("ul")
    
        return this;
      }
    });
    

    希望对你有帮助!!

    【讨论】:

    • 旋风,谢谢你的回答。事实上,这几乎就是我正在做的事情。 parentEl 属性指向 CollectionViews el 属性(它是一个 ul),这样我就可以在 ul 中渲染我的 ChildViews。在我的父 CollectionView 中,我遍历集合模型并为每个模型创建一个 ChildView 实例。我有一种感觉,这种做法是完全错误的。
    • 嗯,这就是我一直在关注的,对我来说效果很好:)
    • 阅读this实际上解决了我的问题。请参阅下面的评论。再次感谢您的意见。
    【解决方案2】:

    通过引入 parentEl 属性并规避视图元素的创建,您有一种禁用的骨干自然行为。您基本上永远不会将视图 `elz 属性连接到任何东西。

    如果我的代码正确,TenantView 是租户列表中的单个列表项。

    在您的TenantView 中,您可以这样做以利用内置事件的主干:

    render: function() {
        this.setElement(this.template.render(this.model));
        $(this.parentEl).children('ul').append(this.$el);
        return this;
    }
    

    setElement 函数将使用 template 函数的返回值来连接视图元素并为您设置事件。在文档中,建议使用setElement,而不是将某些内容分配给el 属性。还有一个漂亮的 $el 属性,它将包含视图元素的缓存 jQuery(或 Zepto)对象。

    为了更多地以主干方式我个人会考虑这样的事情:

    var TenantView = Backbone.View.extend({
        // =========
        // = Setup =
        // =========
    
        events: {
            "click": "setActive"
        },
    
        template: new EJS({
            url: '/scripts/templates/tenant.ejs'
        }),
    
        // =============
        // = Lifecycle =
        // =============
    
        initialize: function(model, options) {
            this.render();
        },
    
        render: function() {
            var content = this.template.render(this.model);
            this.$el.html(content);
            return this;
        },
    
        // ==========
        // = Events =
        // ==========
    
        setActive: function(event) {
            return this.model.set('active', true);
        }
    
    });
    
    
    var TenantList = Backbone.View.extend({
    
        // =========
        // = Setup =
        // =========
    
        id: "tenantList",
        tagName: "ul",
    
        // =============
        // = Lifecycle =
        // =============
    
        initialize: function() {
            this.render();
        },
    
        render: function() {
            if (this.collection.length > 0) {
                this.renderChildren();
            }
        },
    
        renderChildren: function() {
            var that = this;
    
            this.collection.each(function(tenant) {
                that.$el.append(new TenantView(tenant).$el);
            });
        }
    });
    

    【讨论】:

    • 托斯滕,感谢您的回复。 setElement 现在似乎在渲染期间正确设置了我的视图的 el 属性。不幸的是,无论哪种方式都没有捕获到点击事件。我认为我在 CollectionView 中呈现 ChildViews 的整个方法是完全错误的。
    • 嗯,在某种程度上...... Backbone 有点希望你在初始化后有一个元素,并且只用渲染函数填充它。理论上,setElement 函数应该处理事件。您使用哪个版本的骨干网?
    • 我使用的是 0.9.2。到目前为止,解决问题的方法是将 ChildView 的 tagname 设置为“li”。然后从模板中删除 li 。我将 ChildView 的渲染方法更改为:this.el.innerHTML = this.template.render(this.model),并将 CollectionView 的渲染方法更改为:$(this.el).children('ul')。 append(viewInstance.render().el) 迭代 viewInstance 的地方。我仍然不确定这种方法是否正确。
    猜你喜欢
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 2014-02-26
    • 1970-01-01
    • 2015-07-26
    • 1970-01-01
    • 1970-01-01
    • 2015-01-18
    相关资源
    最近更新 更多