【问题标题】:Backbone view not initialising correctly after back or forward button后退或前进按钮后主干视图未正确初始化
【发布时间】:2014-05-21 18:00:30
【问题描述】:

所以我有一个单页主干应用程序,它通过 AJAX 加载新页面并使用历史 API 更新 URL。这一切都很好,但是当我按下后退按钮时,它只是将 URL 更改回来并且不会加载以前的 AJAX。

所以我已经开始解决这个问题,但是我遇到了一个奇怪的问题,即调用了以前的 AJAX,正确加载但无法正常工作,因为我收到以下错误:

this.el is undefined

我真的不知道如何解决这个问题,这是我的一些代码:

ContainerView = Backbone.View.extend({
el: 'body',
events: {
    'click .navigation-item': 'loadRequestedPage'
},
initialize: function() {
    this.listenTo(Backbone, 'popstate', this.onPopState);
},
onPopState: function(e) {
    var pageName = window.location.pathname.substring(window.location.pathname.lastIndexOf('/') + 1, window.location.pathname.lastIndexOf('php') + 3);
    $('.navigation-item[href="'+pageName+'"]').eq(0).click();
},
....
loadRequestedPage: function(e) {
    if (Modernizr.history) {
        e.preventDefault();

        var pageModel = myWebsite.where({pageID: currentPage})[0],
            requestedPageID = $(e.currentTarget).data('page-id'),
            requestedPageModel = myWebsite.where({pageID: requestedPageID})[0],
            requestedPageUrl = requestedPageModel.get('pageUrl'),
            $targetElement = this.determineTargetElement(requestedPageID);

        this.closeMobileNavigation();

        this.loadNewPage(requestedPageModel, requestedPageUrl, requestedPageID, $targetElement);

        this.setActiveNavItem(requestedPageUrl);
        this.updateCurrentPage(requestedPageID);
        this.gaTrackEvent('Page Navigation', requestedPageUrl, 'User used the main navigation to navigate to' + requestedPageUrl);
    }
},

loadRequestedPage 内部的函数继续触发history.pushstate,然后触发backbone.router,最后启动所需的view

手动单击.navigation-item 时效果很好,但在单击后退按钮后通过 JS 触发时效果不佳。

如果有人能提供帮助,那就太棒了。

谢谢。

编辑

这是我的路由器

var app = app || {};

(function($) {

    var Router = Backbone.Router.extend({
        routes: {
            '': 'instantiateHome',
            'index.php': 'instantiateHome',
            'our-approach.php': 'instantiateOurApproach',
            'our-work.php': 'instantiateOurWork',
            'people.php': 'instantiatePeople',
            'social.php': 'instantiateSocial',
            'contact-us.php': 'instantiateContactUs',
            "*notFound" : 'notFound'
        },
        instantiateHome: function() {    
            if(app.home_view == null) {
                app.home_view = new app.HomeView();
            }
        },
        instantiateOurApproach : function() {
            if(app.our_approach_view == null) {
                app.our_approach_view = new app.OurApproachView();
            }
        },
        instantiateOurWork: function() {
            if(app.our_work_view == null) {
                app.our_work_view = new app.OurWorkView();
            }
        },
        instantiatePeople: function() {
            if(app.people_view == null) {
                app.people_view = new app.PeopleView();
            }
        },
        instantiateSocial: function() {
            if(app.social_view == null) {
                app.social_view = new app.SocialView();
            }
        },
        instantiateContactUs: function() {
            if(app.contact_us_view == null) {
                app.contact_us_view = new app.ContactUsView();
            }

        },
        notFound: function() {
            if(app.not_found_view == null) {
                app.not_found_view = new app.NotFoundView();
            }

        }
    });

    app.router = new Router();

    var location_pathname = window.location.pathname;
    var site_url = location_pathname.replace(location_pathname.split("/").pop(),"");
    var urlArray = location_pathname.split("/");
    var pageUrl = urlArray[urlArray.length-1];
    if (Modernizr.history) {
        Backbone.history.start({pushState: true, root: site_url});
    } else {
        Backbone.history.start({hashChange: false, root: site_url});
    }

    app.router.navigate(pageUrl, {trigger: true});

})(jQuery);

编辑

所以我发现按下后退按钮会触发路由器,而无需执行以下代码:

app.router.navigate(pageUrl, {trigger: true});

通常我在 AJAX 调用完成后运行上面的代码,所以我知道在新视图实例化之前所有元素都在页面上。

所以我想我现在的问题是:如何阻止后退按钮触发路由器?

编辑

依赖ajaxComplete()的新路由器代码

instantiateOurWork: function() {
    if (app.ajaxActive) {
        $(document).ajaxComplete(function() {
            if(app.our_work_view == null) {
                app.our_work_view = new app.OurWorkView();
                $(document).unbind('ajaxComplete');
            }
        });
    } else {
        if(app.our_work_view == null) {
            app.our_work_view = new app.OurWorkView();
        }
        app.ajaxActive = true;
    }
},

这确实是一个混乱的代码,但我不知道该怎么做。

【问题讨论】:

  • 您的骨干路由器是什么样的?
  • @SteamDev 我已经为你添加了路由器。
  • 所以问题是在ajax调用完成之前点击返回?你能像if (view.isFetching) return;那样在路由器中添加一个检查吗?
  • 嘿@Vic - 感谢您的评论,所以我实际上已经将我的路由器更改为依赖$(document).ajaxComplete() 现在这意味着它可以工作,但它是非常混乱的代码,我会更新我的问题举个例子。我现在的问题是,当我快速按下后退按钮时,从以前的视图(如 $.each())和类似的功能仍然运行,并导致错误

标签: javascript jquery ajax backbone.js


【解决方案1】:

好的,我已经弄清楚了,这不是一个漂亮的景象,但我不确定我还能怎么做。

首先,我需要确保在开始加载新视图之前所有 ajax 调用都已结束,这将防止多个视图同时存在并停止任何 JS 错误,这是通过以下代码完成的,该代码也可以在我上面的编辑之一:

instantiateOurWork: function() {
    if (app.ajaxActive) {
        $(document).ajaxComplete(function() {
            if(app.our_work_view == null) {
                app.our_work_view = new app.OurWorkView();
                $(document).unbind('ajaxComplete');
            }
        });
    } else {
        if(app.our_work_view == null) {
            app.our_work_view = new app.OurWorkView();
        }
        app.ajaxActive = true;
    }
},

app.ajaxActive是一个全局变量,默认设置为false,这是因为初始页面加载不执行AJAX调用,然后设置为true,这意味着它总是期望AJAX调用正在运行并使用ajaxComplete 函数等待它完成。

我必须处理的下一个问题是终止在后台运行的代码,例如 getScript()$.each 循环会导致错误,因为它们会在视图被删除后尝试运行。

为了解决这个问题,我必须实现默认设置为 false 的局部变量 this.stopExecution

当我的 this.removeView() 函数被调用时,this.stopExecution 将被设置为 true

然后在删除视图后可能运行的任何代码中,我添加了以下代码:

if(self.stopExecution) {
    return false;
}

这将停止代码运行并防止任何错误。

如果有人有更好的解决方案,请随时分享。

谢谢。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多