如何从骨干视图中正确删除任何必要的内容?

时间:2013-10-28 20:15:16

标签: javascript jquery backbone.js

嘿我尝试删除所有内容后,在使用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;
});

1 个答案:

答案 0 :(得分:1)

这是因为每次创建视图时都会重复使用相同的DOM元素#Sirius。在初始化时,Backbone视图将DOM事件委托给它们的顶级节点,包含$el

在删除视图时,清除是自动的,因为节点已从DOM中删除。当您在不删除节点的HTML时替换节点的HTML时,永远不会删除事件处理程序,即使在其内容不再位于DOM中之后,也会保留旧视图以响应点击事件。

有几种方法可以解决这个问题。

  1. 渲染可替换内容时,请勿直接渲染到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);
    
  2. 重复使用相同的视图,更新其实例变量而不是替换它。这对于分页特别有意义,你在迭代一组内容但结构保持不变。

    // 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);
    
  3. 清理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(...);
    
  4. 不要做#3。 1或2更合适。