Pie*_*nna 4 javascript backbone.js
我正在努力了解骨干,目前正在与僵尸观点进行斗争.我已经阅读了很多关于此事的堆栈溢出帖子,但我仍然无法弄明白.
为简单起见,我设置了两个需要切换的视图(没有数据).到目前为止我做的是:
//define application object
var app = {
vent: {},
templates: {},
views: {},
routers: {},
};
//instantiate event aggregator and attach it to app
app.vent = _.extend({}, Backbone.Events);
定义两个非常简单的模板(存储到app.templates中):第一个有一些虚拟文本和一个按钮(带有和'test-begin'的id),第二个只有虚拟文本
定义两个视图
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();
});
}
};
因此,为了检查僵尸视图,第二个视图触发和事件(仍然是:alive)第一个视图通过发送到console.log的消息来监听并响应它(尽管它确实不应该).第一个视图确实收听了这样的消息(在控制台日志中我读到'我还活着),即使它被第二个视图替换了.
你能帮助我吗?非常感谢你.
很长的帖子,如果您有任何疑问,请询问
僵尸视图只是一个不在DOM中的视图,但是监听事件并对事件作出反应 - 有时这种行为是预期的,但通常不是.
如果未正确删除视图的DOM事件处理程序,则不会对视图及其内存中的HTML片段进行垃圾回收.如果Backbone.Event处理程序未正确绑定,您可能会遇到各种不良行为...例如一堆"Zombie"视图在模型上触发AJAX请求.此问题在旧版本的Backbone之前非常常见stopListening,listenTo特别是如果您在视图之间共享模型.
在您的代码中,您没有Zombie View,因为您正在关闭视图.
您可以看到,console.log因为您still:alive在关闭第一个视图之前初始化第二个视图(并触发事件).
要切换视图,您要调用:
mainApp.viewsManager.rederView(new app.views.test());
Run Code Online (Sandbox Code Playgroud)
调用new app.views.test()初始化第二个视图,该视图触发第一个侦听的事件.
如果您将代码更新为以下内容,则不会再看到console.log.
//baseRouter controller
var baseController = {
instructions: function() {
mainApp.viewsManager.rederView(app.views.instructions);
},
beginTest: function(options) {
mainApp.viewsManager.rederView(app.views.test);
},
};
Run Code Online (Sandbox Code Playgroud)
并更新rederView
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);
},
Run Code Online (Sandbox Code Playgroud)
如果你从close方法中删除这一行,你将有一个僵尸视图,应该看到console.log.
//unbind any model and collection events that the view is bound to
this.stopListening();
Run Code Online (Sandbox Code Playgroud)
在下面的代码中,我创建了100个视图,但只在DOM中显示1个.每个视图都包含相同的模型并监听它的change事件.<button>单击视图的元素时,它会更新模型,导致每个视图的模型更改处理程序被执行,调用fetch 100次... 100个AJAX请求!
视图的更改处理程序被调用100次,因为视图关闭方法不会调用this.stopListening(),因此即使从页面中删除视图,它们仍然会监听模型的事件.单击该按钮后,模型将更改,并且所有僵尸视图都会响应,即使它们不在页面上也是如此.
var TestView = Backbone.View.extend({
tagName: 'h1',
initialize: function(options) {
this.i = options.i;
this.listenTo(options.model, 'change', function(model) {
model.fetch();
});
},
events: {
'click button': function() {
this.model.set("show_zombies", Date.now());
}
},
render: function() {
this.$el.append("<button>Click To Test for Zombies!</button>");
return this;
},
close: function() {
this.$el.empty(); // empty view html
// this.$el.off(); // // Whoops! Forgot to unbind Event listeners! (this view won't get garbage collected)
// this.stopListening() // Whoops! Forgot to unbind Backbone.Event listeners.
}
});
var model = new (Backbone.Model.extend({
fetch: function() {
document.body.innerHTML += "MODEL.FETCH CALLED<br />"
}
}));
var v;
for (var i = 1; i < 101; i++) {
if (v) v.close();
v = new TestView({
'i': i,
'model': model
}).render();
$('body').html(v.el);
}Run Code Online (Sandbox Code Playgroud)
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone.js"></script>Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
781 次 |
| 最近记录: |