2015-10-04 3 views
0

Суть этого вопроса заключается в том, что если я использую код Backbone.js для очистки моих представлений (т. Е. Для предотвращения представлений о зомби), то я не могу установить элемент если я нажму кнопку «Назад» в браузере, и поэтому представление не будет отображаться правильно в ситуациях, когда я нажимаю кнопку «Назад».Как запустить конструктор View при использовании кнопки назад браузера

Подробности

У меня есть PostsView, который отображает список сообщений. В конструкторе я называю SetElement, а затем сделать каждый элемент списка с помощью нескольких PostListViews

export class PostsView extends Backbone.View{ 
     constructor(options){ 
     this.setElement($('#main'), true) 
     super() 
     this.render() 
     } 
     addEachPost(model){ 
     new PostListView({model: model }); 
     } 
     render(){ 
     this.collection.each(this.addEachPost, this); 
     } 

Если я нажимаю один из PostListViews, то маршрутизатор нагрузки, PostListView на страницу, и если я нажимаю кнопку назад, он перезагружает представление Posts на странице, но только если я не очистил вид Posts. Например, с помощью этого кода ниже (который не очищает просмотры) я могу нажать кнопку «Назад», а затем еще одну ссылку и так далее, и он продолжает загружать все в порядке, но это будет в конечном итоге создать зомби, потому что я не очистки мнения

маршрутизатор

export class MyRouter extends Backbone.Router{ 

      constructor(options){ 
       '': 'renderList', 
       'post/:id': 'showPost' 
      } 
      renderList(){ 
      new PostsView({collection: this.collection)}; 
      } 
      showPost(id){ 
      //code ommitted 
      new PostView({model: modle}) 
      } 

} 

Итак, с приведенным ниже кодом я ввел некоторый часто используемый код (который я видел в других приложениях Backbone), чтобы предотвратить появление зомби, но теперь, если я это сделаю, когда я нажму кнопку «Назад», PostView doesn «т получить оказанные страницы

код

маршрутизатора, чтобы очистить зомби

changeView(view){ 
    if (this.currentView){ 
     this.currentView.close(); 
    } 
    this.currentView = view; 

} 

в маршрутизаторе, я затем загрузить взгляды по телефону

  `this.changeView(new PostsView({collection: this.collection)});` 

Однако, если я делаю это, я могу загрузить PostsView изначально, но если я нажму на один из членов списка, а затем на задний план, вид Posts не загружается на страницу. Я заметил из проверки консоли, что в этой ситуации (после нажатия кнопки «Назад») el не установлен на #main, поэтому он не попадает на страницу. В коде, где я НЕ Убираю виды зомби, el по-прежнему установлен на #main, если я нажму кнопку «Назад» - очевидно, что мой код для очистки представлений зомби делает что-то, чтобы предотвратить #main being если я нажму кнопку «Назад». Итак, очистив зомби, я удалил el, и он не будет установлен снова, потому что конструктор не запускается, когда я нажимаю кнопку back.

Вопрос: существует ли какой-либо способ использования кода маршрутизатора, который очищает представления зомби, но в то же время, чтобы гарантировать, что конструктор запускается, когда я нажимаю кнопку «Назад» в браузере? Если конструктор для представления запускается, даже когда я нажимаю кнопку «Назад», то я считаю, что он установит элемент (как это было при загрузке страницы)

+0

Не могли бы вы исправить ваш вопрос: предложение, кажется, остановиться посередине на '[.. .] the vi' (просто отредактируйте, не комментируйте «отредактированный», спасибо :) –

+0

@ try-catch-finally ok, я исправил эту часть и попытался уточнить больше в других местах. Спасибо, что указали это. – Leahcim

ответ

1

Я не вижу из вашего кода, который вы называете View.remove(), но предположим, что он внутри this.currentView.close() - remove function (http://backbonejs.org/#View-remove) выполняет правильную очистку, но также удаляет # основной элемент со страницы. Поэтому, если у вас больше просмотров, разделяющих один и тот же (существующий) элемент, вы не можете вызвать remove. Вы должны выполнить очистку, вызвав undelegateEvents (для очистки DOM), stopListening (для очистки событий модели), и если другое представление не будет немедленно отображено, вы также можете вызвать это. $ El.html (""), чтобы его удалить.

Я хотел бы предложить, чтобы сделать очистку в переопределяетесь маршрутизатор Выполнит функцию (http://backbonejs.org/#Router-execute)

EDIT:

При создании вида в позвоночнике у вас есть два варианта, как создать свой элемент:

1) либо использовать существующий элемент DOM

var MyView = Backbone.View.extend({ 
 
    // selector text.. 
 
    $el: "#main", 
 
    render: function() { 
 
    // visible immediatelly 
 
    this.$el.html("<p>content</p>"); 
 
    return this; 
 
    } 
 
});

2) или новый элемент, созданный зрения

var MyView = Backbone.View.Extend({ 
 
    // div is default - you don't have to specify it... 
 
    tagName: 'div', 
 
    render: function() { 
 
    // not visible - this.$el is not live DOM element 
 
    this.$el.html("<p>content</p>"); 
 
    return this; 
 
    } 
 
}); 
 

 
// .. 
 
// outer mechanism 
 
var myView = new MyView(); 
 
$("body").append(myView.render().$el);

Во втором случае, это не жить DOM элемента и должны быть добавлены к DOM с помощью какого-либо механизма вне самого представления (потому что представление должно знать только о его элементе, и вам нужно использовать какой-либо элемент выше)

При уничтожении просмотра также имеется несколько сценариев. Если вы вызываете remove() в представлении, он выполняет всю необходимую очистку - он вызывает jQuery's remove(), который деинсталлирует все события DOM (удаляет элемент из DOM!), А также вызывает stopListening() в представлении, которое отталкивает все события модели (Я имею в виду здесь последнюю версию Backbone 1.2.3).

Таким образом, вы обычно используете remove() на типах # 2. Если у вас есть вид типа 1, вы также можете его уничтожить с помощью remove(), но вы не можете создать другой экземпляр, потому что элемент больше не существует (если вы не создаете новый по внешнему механизму, который может быстро вызвать беспорядок в ваш код).) Вместо удаления вы должны выполнить очистку, вызвав view.undelegateEvents() для событий DOM и view.stopListening() для уничтожения ограниченных событий модели. Теперь элемент остается в DOM, и вы можете создать новый экземпляр представления во время предыдущего RIP представления без призраков.

BTW: Вы можете также иметь несколько представлений, разделяющих один и тот же элемент - один для рендеринга, другой для обработки (логически сгруппированных) событий - тогда вы должны использовать очистку без удаления, если не хотите закрыть только один из них (или временно переключите какое-либо поведение).

Что касается Вашего дела - это сочетание того, что я только что описал:

// .. 
 
// #2 type view 
 
var PostListItemView = Backbone.View.extend({ 
 
    tagName: "li", 
 
    render: function() { 
 
    this.$el.html('<a href="#posts/' + this.model.getId() + '">' + this.model.getName() + '</a>'); 
 
    return this; 
 
    } 
 
}); 
 

 
// .. 
 
// #1 type view 
 
var PostDetailView = Backbone.View.extend({ 
 
    $el: "#main", 
 
    render: function() { 
 
    this.$el.html(/* ... */); 
 
    return this; 
 
    }, 
 
    close: function() { 
 
    this.undelegateEvents(); 
 
    this.stopListening(); 
 
    } 
 
}); 
 

 
// .. 
 
// #1 type view 
 
var PostsListView = Backbone.View.extend({ 
 
    $el: "#main", 
 
    render: function() { 
 
    var $list = $("<ul></ul>"); 
 
    
 
    // you need to store reference to the item views 
 
    this.postListLtemViews = this.collection.reduce(function (list, item) { 
 
     var postListItemView = new PostListItemView({ 
 
     model: item 
 
     }); 
 
     
 
     // 'outer mechanism' to insert #2 type view to DOM 
 
     $list.append(postListItemView.render().$el); 
 
     list.push(postListItemView); 
 
     
 
     return list; 
 
    }, []); 
 
    
 
    this.$el.html($list); 
 
    return this; 
 
    }, 
 
    close: function() { 
 
    _.each(this.postListLtemViews, function (postListItemView) { 
 
     postListItemView.remove(); 
 
    }); 
 
    this.undelegateEvents(); 
 
    this.stopListening(); 
 
    } 
 
}); 
 

 
// .. 
 
// Router 
 
var App = Backbone.Router.extend({ 
 

 
    routes: { 
 
    "posts": "postsList", 
 
    "posts/:id": "postDetail" 
 
    }, 
 

 
    execute: function (callback, args, name) { 
 
    // Cleanup 
 
    if (this.currentView) { 
 
     this.currentView.close(); 
 
    } 
 
    
 
    // Apply route function 
 
    if (callback) { 
 
     callback.apply(this, args); 
 
    } 
 
    }, 
 
    
 
    postsList: function() { 
 
    this.currentView = new PostsListView({ 
 
     collection: ... 
 
    }); 
 
     
 
    this.currentView.render(); 
 
    }, 
 

 
    postDetail: function (id) { 
 
    this.currentView = new PostDetailView({ 
 
     model: ... 
 
    }); 
 
     
 
    this.currentView.render(); 
 
    } 
 

 
});

+0

Большое спасибо, но если я не «удаляю» представления, каждый раз, когда я перехожу из списка, чтобы показать член списка, я каждый раз создаю просмотр списка в маршрутизаторе, а также новый просматривать каждый раз, когда я просматриваю элемент. Не все ли эти новые создания PostView накапливаются и создают проблему? какая из ваших методов очистки справляется с этим? можете ли вы показать мне пример кода, как бы вы переопределили «Router-execute», чтобы справиться с этим? – Leahcim

+0

Не могли бы вы показать мне, как реализована функция this.currentView.close()? Потому что это не стандартная функция просмотра ... –

+0

ОК, я неправильно прочитал ваш комментарий, поэтому в функции закрытия есть «удалить». Я обновлю свой ответ на примере кода. –