嘿我尝试删除所有内容后,在使用this.close()触发上一个或下一个函数后调用搜索视图文件中的close函数,但它正在删除完全影响导航功能的视图...我想知道如何在完成后删除所有内容,否则在路由器中多次出现vent.on。
这是我的路由器文件:
define([
'jquery',
'underscore',
'backbone',
'views/page',
'models/search',
'views/search',
'text!templates/search.html',
'models/song',
'text!templates/song.html'
], function($, _, Backbone, PageV, SearchM, SearchV, SearchT, SongM, SongT) {
var vent = _.extend({}, Backbone.Events);
var currentView, page, search;
Backbone.View.prototype.close = function () {
this.remove();
this.unbind();
if (this.onClose) {
this.onClose();
}
};
var AppRouter = Backbone.Router.extend ({
routes: {
'page/:id': 'showPage',
'search': 'showView'
}
});
var initialize = function () {
var app_router, songPages;
app_router = new AppRouter;
vent.on('loadPage', function (id) {
console.log('hit loaded page');
var newPage = 'page/' + id;
if(id < songPages && id >= 0 ) {
app_router.navigate(newPage, true);
} else {
app_router.navigate('search', true);
}
})
console.log('router file hit');
app_router.on('route:showPage', function (id) {
console.log('page rendered');
var songs, collected, songM, start;
songM = new SongM();
songM.localStorage = new Backbone.LocalStorage("music");
songM.localStorage.findAll().forEach(function (i) {
collected = i;
});
songPages = Math.ceil(collected.music.length / 25); //10 pages
start = id * 25;
songs = collected.music.splice(start, 25);
var titles = {
week: collected.week,
year: collected.year,
channel: collected. channel
};
var currentId = parseInt(id);
if (page) {console.log('page is current'); console.log(page); page.remove(); }
page = new PageV({model: songM, collection: songs, vent: vent, titles: titles, theId: currentId });
page.render(id);
//$("#Sirius").html(page.el);
});
app_router.on('route:showView', function () {
console.log('search page loading...');
var cur;
var searchM = new SearchM();
//if (search) {console.log(search); search.remove(); }
search = new SearchV({model: searchM, vent: vent});
//if(cur) {cur.stopListening(); cur.remove(); console.log('cur removed'); }
search.render();
//cur = search;
vent.on('nextPage', printCons);
function printCons () {
console.log('changing pages');
app_router.navigate('page/0', true);
};
});
Backbone.history.start();
};
return {
initialize: initialize
};
});
以下是包含页面视图的页面:
define([
'jquery',
'underscore',
'backbone',
'models/song',
'collections/songs',
'views/song',
'text!templates/page.html',
'text!templates/song.html'
], function($, _, Backbone, Song, Songs, SongV, PageT, SongT){
var Page = Backbone.View.extend({
el: $("#Sirius"),
events: {
"click .prev": "previous",
"click .next": "next"
},
previous: function () {
this.options.vent.trigger('loadPage', this.options.theId - 1);
},
next: function () {
this.options.vent.trigger('loadPage', this.options.theId + 1);
},
render: function () {
var headings = this.options.titles;
var info = {
week: headings.week,
channel: headings.channel,
year: headings.year
}
var pagetemp = _.template( PageT, info);
this.$el.html( pagetemp );
var songColl = this.collection;
var songV = new SongV({collection: songColl});
songV.render();
}
});
return Page;
});
答案 0 :(得分:1)
这是因为每次创建视图时都会重复使用相同的DOM元素#Sirius
。在初始化时,Backbone视图将DOM事件委托给它们的顶级节点,包含$el
。
在删除视图时,清除是自动的,因为节点已从DOM中删除。当您在不删除节点的HTML时替换节点的HTML时,永远不会删除事件处理程序,即使在其内容不再位于DOM中之后,也会保留旧视图以响应点击事件。
有几种方法可以解决这个问题。
渲染可替换内容时,请勿直接渲染到DOM元素中。相反,将其视为一个容器并在其中进行渲染。这样您就可以在不影响原始DOM的情况下删除视图。这是具有可交换视图的页面区域的常用方法。
// somewhere in a higher scope, refer to the page. Note that if you
// don't need to do any cleanup (Events bindings, model cleanup, etc), you
// don't *need* to keep this reference.
var page;
// in your show handler, replace the *contents* of the DOM element rather
// than creating a 2nd view attached to it. This means removing the `el`
// from the view prototype, as well.
if (page) page.remove();
page = new Page(...);
page.render();
$("#Sirius").html(page.el);
重复使用相同的视图,更新其实例变量而不是替换它。这对于分页特别有意义,你在迭代一组内容但结构保持不变。
// somewhere in a higher scope (or on app.page, etc)
var page;
// on the view, clean up the process of "updating" settings with a method,
// something like:
update: function (options) {
this.model = options.model;
this.collection = options.collection;
this.options = options;
}
// then in your show handler, create a new view the first time, then just
// update it rather than replacing it
page || (page = new PageV());
page.update(options);
清理DOM元素的委托事件绑定。我不愿意添加这个,因为1和2都更合适,但这些方法中的任何一种都可能有效:
// kludge level 1: reference the searchview and attempt to clean it
if (page) {
page.undelegateEvents();
page.stopListening(); // if available
// any other cleanup
}
page = new PageV(...);
// kludge level 2: unbind all DOM events from the element
$("#Sirius").off();
var page = new PageV(...);
// kludge level 3: replace the element in the DOM
$("#Sirius").replaceWith('<div id="#Sirius" />');
var page = new PageV(...);
不要做#3。 1或2更合适。