Как добавить событие изменения размера окна в представление с помощью Backbone?

Я пытался прикрепить обработчик к событию изменения размера в одном из представлений Backbone. Проведя некоторое исследование, я обнаружил, что вы можете прикреплять события только к элементу представления или его потомкам.

Это проблема для меня, потому что визуальный эффект, которого я пытаюсь достичь, невозможен с использованием чистого CSS и требует некоторого JS для установки размеров элемента области содержимого на основе окна за вычетом элемента заголовка.

Если у вас возникли проблемы с визуализацией того, что я пытаюсь сделать, представьте себе тонкий заголовок и область содержимого, которая должна занимать оставшееся пространство без обмана фона CSS.

define(
    [
        'jQuery',
        'Underscore',
        'Backbone',
        'Mustache',
        'text!src/common/resource/html/base.html'
    ],
    function ($, _, Backbone, Mustache, baseTemplate) {
        var BaseView = Backbone.View.extend({

            el: $('body'),

            events: {
                'resize window': 'resize'
            },

            render: function () {
                var data = {};

                var render = Mustache.render(baseTemplate, data);

                this.$el.html(render);

                this.resize();
            },

            resize: function () {
                var windowHeight = $(window).height();

                var headerHeight = this.$el.find('#header').height();

                this.$el.find('#application').height( windowHeight - headerHeight );
            }
        });

        return new BaseView;
    }
);

person Eli    schedule 02.02.2012    source источник


Ответы (2)


var BaseView = Backbone.View.extend({

    el: $('body'),

    initialize: function() {
        // bind to the namespaced (for easier unbinding) event
        // in jQuery 1.7+ use .on(...)
        $(window).bind("resize.app", _.bind(this.resize, this));
    },

    remove: function() {
        // unbind the namespaced event (to prevent accidentally unbinding some
        // other resize events from other code in your app
        // in jQuery 1.7+ use .off(...)
        $(window).unbind("resize.app");

        // don't forget to call the original remove() function
        Backbone.View.prototype.remove.call(this);
        // could also be written as:
        // this.constructor.__super__.remove.call(this);
    }, ...

Не забудьте вызвать функцию remove() в представлении. Никогда не заменяйте представление другим.

person roberkules    schedule 02.02.2012
comment
Спасибо вам за ваш быстрый ответ! Но является ли плохой практикой выходить за пределы слоя событий Backbone? - person Eli; 02.02.2012
comment
Я бы сказал, не беспокойтесь об этом слишком много. Событие изменения размера не выполняет сложного взаимодействия с вашей структурой MVC, поэтому вы ничего не теряете, просто имея отдельный слушатель. - person wheresrhys; 02.02.2012
comment
Спасибо, что разъяснили мне это - person Eli; 02.02.2012
comment
Вам может понадобиться метод remove в представлении, который отвязывает это событие, вы получите случайные привязки и утечки, если представление будет удалено без закрытия всей страницы. - person mu is too short; 02.02.2012
comment
Хороший ответ, однако ваше удаление отменит все события resize.app, что может быть проблемой, если вы используете это представление более одного раза. - person jantimon; 06.04.2013
comment
@jantimon - пример подходит к вопросу, так как он предназначался для базового представления с «el: $('body')». Мог быть только один. Но, конечно, если вы хотите использовать это в других представлениях, вы должны добавить идентификатор представления в пространство имен событий. - person roberkules; 07.04.2013

Вы можете позволить window.onresize запускать пользовательскую магистралью. js, а затем позволить представлениям или моделям прослушивать это, чтобы получить настраиваемые ответы для различных элементов.

Случай 1. Представление напрямую прослушивает событие окна.

window.onload = function() {

  _.extend(window, Backbone.Events);
  window.onresize = function() { window.trigger('resize') };

  ViewDirect = Backbone.View.extend({

    initialize: function() {
      this.listenTo(window, 'resize', _.debounce(this.print));
    },

    print: function() {
      console.log('Window width, heigth: %s, %s',
        window.innerWidth,
        window.innerHeight);
    },

  });

  var myview = new ViewDirect();

  }

Вариант 2. Вы можете захотеть сохранить размер окна, не проверяя его каждый раз, когда он вам нужен, поэтому вы сохраняете размер окна в магистральной модели: в этом случае оконная модель слушает окно, а представление слушает модель окна:

window.onload = function() {

  _.extend(window, Backbone.Events);
  window.onresize = function() { window.trigger('resize') };

  WindowModel = Backbone.Model.extend({

    initialize: function() {
      this.set_size();
      this.listenTo(window, 'resize', _.debounce(this.set_size));
    },

    set_size: function() {
      this.set({
        width: window.innerWidth,
        height: window.innerHeight
      });
    }

  });

  ViewWithModel = Backbone.View.extend({

    initialize: function() {
      this.listenTo(this.model, 'change', this.print);
      ...
    },

    print: function() {
      console.log('Window width, heigth: %s, %s',
        this.model.width,
        this.model.height);
    },
  });

  var window_model = new WindowModel();
  var myview = new ViewWithModel({model: window_model});

}
person Luca Bonavita    schedule 09.09.2013
comment
есть ли причина, по которой модель участвует в этом процессе событий? Обычно я думаю об изменении размера как о событии слоя просмотра. - person mlibby; 01.11.2013
comment
@mlibby это зависит от того, что меняется. Возможно, событие изменит модель, так что представление будет иметь дело только с событиями из модели. - person prodaea; 27.12.2013
comment
Привет, @mlibby, извини за поздний повтор, я не заметил твоего вопроса. Отредактировано, чтобы ответить, а также отметить, что prodaea сказал выше. - person Luca Bonavita; 30.12.2013