【问题标题】:backbone view events don't work after re-render重新渲染后主干视图事件不起作用
【发布时间】:2012-03-14 10:57:17
【问题描述】:

我正在拔头发,在视图重新渲染后,我似乎无法让鼠标事件在我的主干视图上工作,除非我做了最荒谬的事情:

$("a").die().unbind().live("mousedown",this.switchtabs);

我实际上有这个,但决定更新到最新的主干并尝试使用新的delegateEvents()function。

这是我的项目 ID 的结构方式:

Appview / AppRouter
  |
  ----->PageCollection
             |
             ------->PageView/PageModel
             ------->PageView/PageModel      these page view/models are not rendered
             ------->PageView/PageModel
             |
             ------->PageView/PageModel
                        |
                        ----->render()      *when a pageview is rendered*
                                |
                                -----> Creates new 
                                     Tabcollection
                                       |
                                       --->TabModel/TabView   <-- this is where the issue is 

发生的情况是 tabcollection 有一个主 tabview 来管理所有选项卡,然后为每个选项卡创建一个新的模型/视图,并放置一个侦听器以在加载选项卡时重新呈现 tabview。如果 tabview 被重新渲染,鼠标事件将不再起作用,除非我把那个人为的 jQuery 语句放在那里。

这是 tabview 和渲染(我把它剥离了很多)

var TabPanelView = Backbone.View.extend({
    className:      "tabpanel",
    html:           'no content',
    model:          null,
    rendered:       false,
    events:{
        'click a.tab-nav': 'switchtabs'
    },
    initialize: function(args)
    {
        this.nav            = $("<ol/>");
        this.views          = args.items;
        this.className      = args.classname?args.classname:"tabpanel";
        this.id             = args.id;
        this.container      = $("<section>").attr("class",this.className).attr("id",this.id);
        _.bindAll(this);
        return this.el
    },
    /*
    This render happens multiple times, the first time it just puts an empty html structure in place
    waiting for each of the sub models/views to load in (one per tab)
    */
    render: function(args){
        if(!args)
        {
            //first render
            var nav             = $("<aside/>").addClass("tab-navigation").append("<ol/>").attr("role","navigation");
            var tabcontent      = $("<section/>").addClass("tab-panels");
            for(i = 0;i<this.views.length;i++)
            {
                $("ol",nav).append("<li><a rel='"+this.views[i].id+"' href='javascript:;' class='tab-nav'></a></li>");
                tabcontent.append(this.views[i].el);
            }
            this.$el.empty().append(nav).append(tabcontent);
        }
        else if(args && args.update == true){
            // partial render -- i.e. update happened inside of child objects
            var targetid = args.what.cid;
            for(i = 0;i<this.views.length;i++)
            {
                var curcontent  = this.$el.find("div#"+this.views[i].id);
                var curlink     = this.$el.find("a[rel='"+this.views[i].id+"']")
                if(this.views[i].cid == targetid)
                {
                    curcontent.html($(this.views[i].el).html());
                    curlink.text(this.views[i].model.rawdata.header);
                }
                if(i>0)
                {
                    // set the first panel 
                    curcontent.addClass("tab-content-hide");
                }
                if(i==0)
                {
                    curcontent.addClass("tab-content-show");
                    curlink.addClass("tab-nav-selected");
                }
                // this ridiculous piece of jQuery is the *ONLY* this i've found that works
                //$("a[rel='"+this.views[i].id+"']").die().unbind().live("mousedown",this.switchtabs);
            }
        }
        this.delegateEvents();
        return this;
    },
    switchtabs: function(args){

        var tabTarget = args.target?args.target:false
        if(tabTarget)
        {
            this.$el.find("aside.tab-navigation a").each(function(a,b)
            {
                $(this).removeClass("tab-nav-selected")
            })
            $(tabTarget).addClass("tab-nav-selected");
            this.$el.find("div.tab-content-show").removeClass("tab-content-show").addClass("tab-content-hide");
            this.$el.find("div#"+tabTarget.rel).removeClass("tab-content-hide").addClass("tab-content-show");
        }
    }
});

谁能想到为什么主干鼠标事件根本不触发,是因为它们不在 DOM 上吗?我认为这是主干特别有用的地方?...

【问题讨论】:

  • 到目前为止,您采取了哪些措施来解决此问题?我会尝试几件事:看看您是否可以在处理events 元素的主干源中设置断点。或许能给你一些启示。另外,尝试使用 Chrome 的 DOM 和事件监听器断点。这可能会帮助您检查是否正在执行任何代码,或者事件是否只是未能连接。
  • 我已经记录了 jq $(document).find("tab-nav-selected") 以查看渲染的项目是否实际上在 dom 上......很好得到正确的结果。在我自己的代码中经历了断点。我对它没有足够的信心用调试器去挖掘主干本身。范围似乎都很好......我无论如何都不确定,但似乎事件要么由于重新渲染而被覆盖,要么......嗯

标签: javascript jquery backbone.js underscore.js backbone-events


【解决方案1】:

这行代码很可能是你的问题:

this.delegateEvents();

删除它,它应该可以工作。

您唯一需要自己调用delegateEvents 的情况是,当您有独立于视图的events 散列声明的事件时。当您创建视图的实例时,Backbone 的视图会为您调用此方法。

【讨论】:

  • 遗憾的是没有骰子。很荣幸能得到你的回答,我在你的博客上读到了一堆有用的主干资料。我已经放弃并选择了 jQuery.live... 是的,这是一个可憎的东西.. 但这是唯一有效的方法,我还有 2 天的时间......嗯
【解决方案2】:

当视图被重新渲染时,你是在重用同一个视图并再次调用它的 render(),还是你删除视图并创建一个全新的视图?

无论哪种方式,看起来原因是在重新渲染视图之前视图事件没有被解除绑定。 Derick Bailey 对此有很好的post

重新渲染时,1) 确保取消绑定旧视图中的所有事件,2) 创建一个新视图并进行渲染

【讨论】:

  • 不错的文章,但是当每个子视图更新时,我无法制作新的父视图(父视图必须响应子视图)。奇怪的是,我尝试了文章中的方法,但奇怪的是,它在我重新加载页面的每 3 次中大约有 1 次起作用......没有
【解决方案3】:

当使用$(el).empty() 时,它会删除所选元素中的所有子元素并删除所有事件(和数据)绑定到任何 ( child) 元素 在所选元素 (el) 内。

将事件绑定到 子元素,但仍要移除子元素,请使用:

$(el).children().detach(); 而不是$(.el).empty();

这将允许您的视图成功地重新渲染,而事件仍然绑定和工作。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-13
相关资源
最近更新 更多