Javascript 再次讨论主干僵尸视图

Javascript 再次讨论主干僵尸视图,javascript,backbone.js,Javascript,Backbone.js,我正在努力理解主干,目前正在与僵尸观点作斗争。我已经读了很多关于这个问题的文章,但是我仍然无法理解 为了简单起见,我设置了两个需要切换的视图(没有数据)。 到目前为止,我所做的是: 创建对象 //定义应用程序对象 变量应用={ 通风口:{}, 模板:{}, 视图:{}, 路由器:{}, }; //实例化事件聚合器并将其附加到应用程序 app.vent=\ u0.extend({},Backbone.Events); 定义两个非常简单的模板(存储在app.templates中):第一个模板有一些伪

我正在努力理解主干,目前正在与僵尸观点作斗争。我已经读了很多关于这个问题的文章,但是我仍然无法理解

为了简单起见,我设置了两个需要切换的视图(没有数据)。 到目前为止,我所做的是:

  • 创建对象
  • //定义应用程序对象 变量应用={ 通风口:{}, 模板:{}, 视图:{}, 路由器:{}, }; //实例化事件聚合器并将其附加到应用程序 app.vent=\ u0.extend({},Backbone.Events);
  • 定义两个非常简单的模板(存储在app.templates中):第一个模板有一些伪文本和一个按钮(id为'test begin'),第二个模板只是伪文本

  • 定义两个视图

  • app.views.instructions=Backbone.View.extend({ //加载下划线模板 模板:u.template(应用模板说明), //在实例化时自动调用 初始化:函数(选项){ //将相关功能绑定到视图 _.bindAll(这是“render”、“testBegin”、“stillAlive”、“beforeClose”); //收听app.vent事件 this.listenTo(app.vent,'still:alive',this.stillAlive); }, //将事件绑定到DOM元素 活动:{ '单击#测试开始':'测试开始', }, //渲染视图 render:function(){ this.el.html(this.template()); 归还这个; }, //开始测试 testBegin:function(){ Backbone.history.navigate('begin',{trigger:true}); }, //还活着 stillAlive:function(){ log(“我还活着”); }, //关门前 beforeClose:function(){ //停止收听app.vent 停止监听(app.vent); }, }); //测试视图 app.views.test=Backbone.View.extend({ //加载下划线模板 模板:u.template(app.templates.test), //在实例化时自动调用 初始化:函数(选项){ //触发器仍然:活动,并查看移除的视图是否响应它 app.vent.trigger('still:alive'); //将相关功能绑定到视图 _.bindAll(这是“呈现”); }, //渲染视图 render:function(){ this.el.html(this.template()); 归还这个; }, });
  • 定义路由器
  • //基本路由器 app.routers.baseRouter=Backbone.Router.extend({ //路线 路线:{ “说明”, “开始”:“开始” }, //函数(属于对象控制器) 指令:函数(){baseController.instructions()}, beginTest:函数(){baseController.beginTest()}, }); //基本路由器控制器 var baseController={ 说明:函数(){ mainApp.viewsManager.rederView(新的app.views.instructions()); }, beginTest:函数(选项){ mainApp.viewsManager.rederView(新的app.views.test()); }, };
  • 定义mainApp(带有视图切换器)
  • //定义主应用程序对象 mainApp={}; //管理视图切换 mainApp.viewsManager={ //罗特尔 rootEl:“#测试容器”, //关闭当前视图并显示下一个视图 rederView:函数(视图,rootEl){ //如果未传递domel,请将其设置为默认RootEl rootEl=rootEl | | this.rootEl; //关闭当前视图 如果(this.currentView)this.currentView.close(); //存储对下一个视图的引用 this.currentView=视图; //渲染下一个视图 $(rootEl).html(this.currentView.render().el); }, }; //呈现应用程序的第一个视图 mainApp.viewsManager.rederView(新的app.views.instructions()); //启动路由器并将其连接到应用程序 mainApp.baseRouter=新建app.routers.baseRouter(); //启动主干历史记录 Backbone.history.start({silent:true) });
  • 通过主干原型向视图添加关闭功能
  • //向主干视图原型添加功能(在所有视图中都可用) Backbone.View.prototype.close=函数(){ //如果在视图中定义了view beforeClose函数,则调用该函数 如果(this.beforeClose)this.beforeClose(); //将从DOM中删除this.el,并清除DOM元素的事件 这个。删除(); //取消绑定视图绑定到的任何模型和集合事件 这个。停止听(); //检查视图是否有子视图 if(此.hasOwnProperty(“U子视图”)){ //循环当前视图的子视图 _(此._子视图)。每个(函数(子视图){ //调用子视图的close方法 child.close(); }); } }; 因此,为了检查僵尸视图,第二个视图触发事件(仍然:活动),第一个视图通过发送到console.log的消息侦听并响应该事件(尽管它确实不应该)。 第一个视图确实会侦听这样的消息(在控制台日志中,我读到‘我仍然活着’),即使它已被第二个视图替换


    你能帮我吗?非常感谢。

    长帖,如果您有任何问题,请询问

    僵尸视图只是一个不在DOM中的视图,它侦听事件并对事件做出反应——有时这种行为是预期的,但通常不是

    如果未正确删除视图的DOM事件处理程序,则不会对视图及其内存中的HTML片段进行垃圾收集。如果主干.Event处理程序未正确解除绑定,则可以 //define application object var app = { vent: {}, templates: {}, views: {}, routers: {}, }; //instantiate event aggregator and attach it to app app.vent = _.extend({}, Backbone.Events); app.views.instructions = Backbone.View.extend({ //load underscore template template: _.template(app.templates.instructions), //automatically called upon instantiation initialize: function(options) { //bind relevant fucntions to the view _.bindAll(this, 'render', 'testBegin', 'stillAlive', 'beforeClose'); //listen to app.vent event this.listenTo(app.vent, 'still:alive', this.stillAlive); }, //bind events to DOM elements events: { 'click #test-begin' : 'testBegin', }, //render view render: function() { this.$el.html(this.template()); return this; }, //begin test testBegin: function() { Backbone.history.navigate('begin', {trigger: true}); }, //still alive stillAlive: function() { console.log('I am still alive'); }, //before closing beforeClose: function() { //stop listening to app.vent this.stopListening(app.vent); }, }); //test view app.views.test = Backbone.View.extend({ //load underscore template template: _.template(app.templates.test), //automatically called upon instantiation initialize: function(options) { //trigger still:alive and see if removed view responds to it app.vent.trigger('still:alive'); //bind relevant fucntions to the view _.bindAll(this, 'render'); }, //render view render: function() { this.$el.html(this.template()); return this; }, }); //base router app.routers.baseRouter = Backbone.Router.extend({ //routes routes: { '': "instructions", 'begin': "beginTest" }, //functions (belong to object controller) instructions: function() {baseController.instructions()}, beginTest : function() {baseController.beginTest()}, }); //baseRouter controller var baseController = { instructions: function() { mainApp.viewsManager.rederView(new app.views.instructions()); }, beginTest: function(options) { mainApp.viewsManager.rederView(new app.views.test()); }, }; //define mainApplication object mainApp = {}; //manages views switching mainApp.viewsManager = { //rootEl rootEl: '#test-container', //close current view and show next one rederView : function(view, rootEl) { //if DOM el isn't passed, set it to the default RootEl rootEl = rootEl || this.rootEl; //close current view if (this.currentView) this.currentView.close(); //store reference to next view this.currentView = view; //render next view $(rootEl).html(this.currentView.render().el); }, }; //render first view of app mainApp.viewsManager.rederView(new app.views.instructions()); //initiate router and attach it to app mainApp.baseRouter = new app.routers.baseRouter(); //start Backbone history Backbone.history.start({silent: true }); //add function to Backbone view prototype (available in all views) Backbone.View.prototype.close = function () { //call view beforeClose function if it is defined in the view if (this.beforeClose) this.beforeClose(); //this.el is removed from the DOM & DOM element's events are cleaned up this.remove(); //unbind any model and collection events that the view is bound to this.stopListening(); //check whether view has subviews if (this.hasOwnProperty('_subViews')) { //loop thorugh current view's subviews _(this._subViews).each(function(child){ //invoke subview's close method child.close(); }); } };
    mainApp.viewsManager.rederView(new app.views.test());
    
    //baseRouter controller
    var baseController = {
    
        instructions: function() {
           mainApp.viewsManager.rederView(app.views.instructions);
    
        },
    
        beginTest: function(options) {
           mainApp.viewsManager.rederView(app.views.test);
        },
    };
    
    rederView : function(ViewClass, rootEl) {   
        //if DOM el isn't passed, set it to the default RootEl
        rootEl = rootEl || this.rootEl;
    
        //close current view
        if (this.currentView) this.currentView.close();
    
        //store reference to next view
        this.currentView = new ViewClass();
    
        //render next view
        $(rootEl).html(this.currentView.render().el);
    },
    
    //unbind any model and collection events that the view is bound to
    this.stopListening();