Backbone.js在删除或关闭后呈现故障

时间:2013-05-25 20:36:55

标签: backbone.js view underscore.js render

我扩展了Backbone的View原型以包含一个“关闭”功能,以“杀死僵尸”,这是我从Derrick Bailey's blog

学到的一种技术

代码如下所示:

Backbone.View.prototype.close = function () {
    this.remove();
    this.unbind();
    if (this.onClose) {
        this.onClose();
    }
};

然后我有一个看起来(大部分)像这样的路由器:

AppRouter = Backbone.Router.extend({

    initialize: function() {
        this.routesHit = 0;
        //keep count of number of routes handled by your application
        Backbone.history.on('route', function () { this.routesHit++; }, this);
    },

    back: function () {
        if(this.routesHit > 1) {
            //more than one route hit -> user did not land to current page directly
            logDebug("going window.back");
            window.history.back();
        } else {
            //otherwise go to the home page. Use replaceState if available so
            //the navigation doesn't create an extra history entry
            this.navigate('/', {trigger:true, replace:true});
        }
    },

    routes: {
        "": "showLoginView",
        "login": "showLoginView",
        "signUp": "showSignUpView"
    },

    showLoginView: function () {
        view = new LoginView();
        this.render(view);
    },

    showSignUpView: function () {
        view = new SignUpView();
        this.render(view);
    },

    render: function (view) {
        if (this.currentView) {
            this.currentView.close();
        }
        view.render();
        this.currentView = view;
        return this;
    }
});

我的LoginView的渲染功能如下所示:

     render: function () {
        $("#content").html(this.$el.html(_.template($("#login-template").html())));
        this.delegateEvents();
        return this;
    }

第一次呈现LoginView时,效果很好。但是如果我渲染一个不同的视图(从而在我的LoginView上调用“close”)然后尝试返回我的LoginView,我会得到一个空白屏幕。我知道我的LoginView上的渲染第二次触发,但似乎我的“关闭”方法导致了问题。有什么想法吗?

编辑在收到Rayweb_on的一些反馈后,似乎我应该添加更多细节并澄清。

我的HTML看起来像这样:

<div id="header">this is my header</div>
<div id="content">I want my view to render in here</div>
<div id="footer">this is my footer</div>

然后我有一个看起来像这样的登录模板(

<script type="text/template" id="login-template">
        <div id="login-view">
            <form>
               ...
            </form>
        </div>
</script>

我试图得到它以便视图总是在“content”div内部呈现,但看起来“close”的调用有效地从DOM中删除了“content”div。因此,“空白”页面。有什么想法吗?

编辑2 以下是我的LoginView看起来的样子,经过一些涂鸦:

LoginView = Backbone.View.extend({
    events: {
        "vclick #login-button": "logIn"
    },

    el: "#content",

    initialize: function () {
        _.bindAll(this, "logIn");
    },

    logIn: function (e) {
       ...
    },


    render: function () {
        this.$el.html(_.template($("#login-template").html()));
        this.delegateEvents();
        return this;
    }

});

我将el设置为“#content”,希望能够重新创建它。但仍然没有运气。事实上,现在当我进入下一页时,它不存在,因为#content正在被立即删除。

我也尝试过:

LoginView = Backbone.View.extend({
    events: {
        "vclick #login-button": "logIn"
    },

    el: "#login-template",

    initialize: function () {
        _.bindAll(this, "logIn");
    },

    logIn: function (e) {
       ...
    },


    render: function () {
        this.$el.html(_.template($("#login-template").html()));
        this.delegateEvents();
        return this;
    }

});

但这根本不起作用。有什么想法吗?

2 个答案:

答案 0 :(得分:1)

当您第一次删除视图时删除视图,所以此行

 $("#content").html(this.$el.html(_.template($("#login-template").html())));
你的渲染功能

不会工作。就这样。$ el。它未定义。

答案 1 :(得分:0)

看来,视图中包含的任何元素都会被我的“关闭”函数破坏(或者至少从DOM中删除)(感谢Rayweb_on!)。所以,如果我在视图中引用#content div,我会在视图关闭后丢失它。因此,我不再在视图中的任何地方引用#content。相反,我将视图的默认“el”添加到我视图外部的#content元素中。

在我的情况下,我选择在路由器中执行此操作。结果如下:

<强> ROUTER

    AppRouter = Backbone.Router.extend({

    initialize: function() {
     ...
    },

    routes: {
        "" : "showLoginView",
        "login": "showLoginView",
        "signUp": "showSignUpView",
    },

    showLoginView: function () {
        view = new LoginView();
        this.render(view);
    },

    showSignUpView: function () {
        view = new SignUpView();
        this.render(view);
    },

    render: function (view)
    {
        if (currentView)
        {
            currentView.close();
        }
        $("#content").html(view.render().el);
        currentView = view;
        return this;
    }

});

登录视图

    LoginView = Backbone.View.extend({
    events: {
        "vclick #login-button": "logIn"
    },

    initialize: function () {
        _.bindAll(this, "logIn");
    },

    logIn: function (e) {
        ...
    },

    render: function () {
        this.$el.html(_.template($("#login-template").html()));
        this.delegateEvents();
        return this;
    }

});

这一切都很有效,但我不确定这是最好的解决方案。我甚至不确定这是一个很好的解决方案,但现在让我感动。我当然乐于接受其他选择。

====

编辑:找到一个稍微清洁的解决方案。

我编写了一个名为injectView的函数,如下所示:

function injectView(view, targetSelector) {
    if (_.isNull(targetSelector)) {
        targetSelector = "#content";
    }
    $(targetSelector).html(view.el);
}

我从每个View的渲染函数中调用它,如下所示:

        render: function () {
        this.$el.html(_.template($("#login-template").html()));
        this.delegateEvents();
        injectView(this,"#content")
        return this;
    }

有效。我不知道它有多好。但它的确有效。