【问题标题】:Backbone.js Render Malfunctioning After Being Removed or ClosedBackbone.js 渲染被移除或关闭后出现故障
【发布时间】:2013-05-25 20:36:54
【问题描述】:

我已经扩展了 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 上调用“关闭”)然后尝试返回我的 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>

我试图让视图始终呈现在该“内容”div 内,但似乎对“关闭”的调用有效地从 DOM 中删除了“内容”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;
    }

});

但这根本行不通。有什么想法吗?

【问题讨论】:

    标签: backbone.js view underscore.js render


    【解决方案1】:

    当您第一次删除视图时,您正在删除它的 el,所以这条线

     $("#content").html(this.$el.html(_.template($("#login-template").html())));
    

    在您的渲染功能上不起作用。就像this.$el。它未定义。

    【讨论】:

    • 我不知道你的模板,所以我无法提供如何正确处理它的问题,但我认为 $("#content").html(_.template($("#login-template" ).html()));应该工作......
    • 感谢 Rayweb_on。您的回答提供了一些见解,经过一些实验,我确定对“关闭”的调用似乎正在从 DOM 中删除 $("#content")。我试过: $("#content").html(_.template($("#login-template").html()));它不起作用。我将编辑我的原始帖子以提供更多见解。
    • 在您的 loginView 中确保将 .el 指定为 #login-template。因此,每当您调用 close 时,删除的元素就是模板插入的 div,每次都可以从模板中重新插入该 div。但内容没有。
    • 很抱歉,没有完全理解。您的意思是在我的 LoginView 中将 el 设置为 #content ... 我将再次编辑我的原始帖子以获取更多信息。感谢您对我的耐心等待。
    • nop, set el : #login-view, 所以每当你关闭视图时,这个元素将被删除,如果你的 el 是 #content 并且你删除了它,那么你将无法插入任何其他观点。我对我之前的评论感到困惑。
    【解决方案2】:

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

    就我而言,我选择在路由器中执行此操作。结果如下所示:

    路由器

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

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

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

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

    【讨论】:

    • 好的。我承认被你最后的解决方案难住了。您是否使用injectView 在#content 向您的DOM 添加内容,而不让您的视图知道#content,这样它就不会在close() 时将其删除?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-27
    • 2019-02-26
    相关资源
    最近更新 更多