Marionette.View

Marionette имеет базовый класс Marionette.View, другие представления расширяют его (наследуются от него). Это базовое представление предоставляет некоторую общую и базовую (core) функциональность, которой могут воспользоваться другие представления.

Замечание: Класс Marionette.View не предназначен для непосредственного использования. Он существует как базовое представление для других классов представлений, они должны расширять его. Задача класса Marionette.View обеспечить общее место для расположения поведений, которые являются общими для всех представлений.

Содержание

Привязка событий к представлению

Marionette.View расширяет Backbone.View. Рекомендуется использовать метод listenTo для прослушивания событий (привязки к событиям) модели, коллекции или других событий от объектов Backbone и Marionette.

var MyView = Marionette.ItemView.extend({
  initialize: function() {
    this.listenTo(this.model, "change:foo", this.modelChanged);
    this.listenTo(this.collection, "add", this.modelAdded);
  },

  modelChanged: function(model, value) {},

  modelAdded: function(model){}
});

Контекст (this) будет автоматически установлен на объект представления. При желании вы можете сами установить контекст с помощью _.bind.

// Мы принудительно устанавливаем контекст функции обратного вызова "reconcileCollection"
// на объект самой collection, этот контекст только для этого обработчика события
// (не влияет на любое другое использование метода "reconcileCollection")
this.listenTo(this.collection, "add", _.bind(this.reconcileCollection, this.collection));

Метод onShow

  • “show” / onShow - Вызывается у экземпляра представления после того, как представление было сформировано (rendered) и отображено.

Это событие можно использовать для реагирования на отображение представления через регион. Все представления, которые наследованы от базового класса Marionette.View имеют эту функциональность, в частности ItemView, CollectionView, CompositeView, и LayoutView.

Marionette.ItemView.extend({
  onShow: function() {
    // вызывается, когда представление было отображено
  }
});

Часто используемая ситуация для метода onShow - это его использование для добавления дочерних представлений.

var LayoutView = Marionette.LayoutView.extend({
   regions: {
     Header: 'header',
     Section: 'section'
   },
   onShow: function() {
      this.Header.show(new Header());
      this.Section.show(new Section());
   }
});

Метод destroy

Представление реализует метод destroy, который вызывается системой управления регионами (менеджерами регионов) автоматически. Как часть реализации, метод destroy выполняет следующие операции:

  • вызывает событие onBeforeDestroy у представления, если таковое имеется
  • вызывает событие onDestroy у представления, если таковое имеется
  • прекращает прослушивание всех пользовательских событий представления
  • прекращает прослушивание всех DOM-событий
  • удаляет this.el из DOM
  • прекращает прослушивание всех listenTo событий
  • возвращает представление.

Реализовывая метод onDestroy в определении вашего представления, позволяет вам запускать пользовательский код для вашего представления, который будет выполнен после того как ваше представление будет уничтожено и очищено. Метод onDestroy будет вызван с аргументами, с которыми был вызван метод destroy. Это позволяет вам выполнить любой дополнительный код по очистке без необходимости переопределения метода destroy.

var MyView = Marionette.ItemView.extend({
  onDestroy: function(arg1, arg2) {
    // свой код очистки или уничтожения, должен быть здесь
  }
});

var myView = new MyView();
myView.destroy(arg1, arg2);

Метод onBeforeDestroy

Когда запускается процесс уничтожения представления, то вызывается метод onBeforeDestroy, если этот метод представлен. Метод onBeforeDestroy вызывается перед уничтожением представления. Он будет вызван с аргументами, с которыми был вызван метод destroy.

Событие “attach” / метод onAttach

Каждое представление в Marionette имеет специальное событие attach, оно срабатывает каждый раз когда представление было добавлено в document. Как и другие Marionette-события, оно вызывает еще и метод onAttach, если он описан. Событие attach отлично подходит для jQuery плагинов или других библиотек, которое должны быть выполнены после того как представление появится в document.

Событие attach срабатывает только когда представление становится дочерним узлом document. Если Region, в котором показывается представление не является потомком document, а вы вызываете метод show, то событие attach не сработает до тех пор пока Region не станет потомком document.

Это событие уникально тем, что оно распространяется вниз по дереву. Например, если в CollectionView срабатывает метод attach, то и во всех дочерних представлениях инициируется событие attach. Кроме того, и в глубоко вложенных структурах Layout View вызовется событие attach.

Для более полного понимания вложенных структур представлений обратитесь к документации LayoutView.

Событие “before:attach” / метод onBeforeAttach

Тоже самое что и событие attach, описанное выше, но срабатывает перед тем как представление будет добавлено в document.

Событие “dom:refresh” / метод onDomRefresh

Вызывается после того, как представление было сформировано (rendered) и отображено в DOM через Marionette.Region, или было пере-сформировано (re-rendered).

Это событие / функция обратного вызова используется DOM-зависимыми UI плагинами таких как jQueryUI или KendoUI.

Marionette.ItemView.extend({
  onDomRefresh: function() {
    // Манипуляции с `el` нужно делать здесь. Оно (`el`) уже было
    // сформировано, и HTML представления готов для использования.
  }
});

Чтобы узнать больше об интеграции Marionette с KendoUI (также применимо к jQueryUI и другим UI виджетам), читайте эту статью в блоге KendoUI + Backbone.

События представления

Поскольку класс Marionette.View расширяет (наследуется от) backbone-ий класс представления, вы получаете преимущества от использования хеша events.

Некоторый синтаксический сахар добавляется от возможности использования хеша ui.

var MyView = Marionette.ItemView.extend({
  // ...

  ui: {
    "cat": ".dog"
  },

  events: {
    "click @ui.cat": "bark" // это эквивалентно "click .dog":
  }
});

Триггеры представления

В представлениях можно определять набор triggers в виде хеша, который будет преобразовывать DOM-события в вызов метода view.triggerMethod.

В хеше triggers слева указываются стандартые DOM-события Backbone.View (“событие селектор”), справой же стороны хеша определяются события представления, которые вы хотите вызвать у представления.

var MyView = Marionette.ItemView.extend({
  // ...

  triggers: {
    "click .do-something": "something:do:it"
  }
});

var myView = new MyView();
myView.render();

myView.on("something:do:it", function(args) {
  alert("I DID IT!");
});

// нажатие ("click") на 'do-something' DOM-элемент
// демонстрирует преобразование DOM-события
myView.$(".do-something").trigger("click");

В результате выполнения этого кода, появится окно предупреждения с текстом “I DID IT!”.

По умолчанию все триггеры (triggers) будут остановлены методами preventDefault и stopPropagation. По желанию вы можете вручную настроить триггеры, используя хэш вместо имени события представления. Пример тригера ниже демонстрирует определение события и предотвращение поведения браузера по умолчанию с помощью только метода preventDefault.

Marionette.CompositeView.extend({
  triggers: {
    "click .do-something": {
      event: "something:do:it",
      preventDefault: true, // этот параметр не является обязательным, по умолчанию его значение true
      stopPropagation: false
    }
  }
});

Вы также можете указать triggers как функцию, которая возвращает хеш сконфигурированных тригеров.

Marionette.CompositeView.extend({
  triggers: function() {
    return {
      "click .that-thing": "that:i:sent:you"
    };
  }
});

Селекторы в триггере могут быть указаны через ситнаксический сахар от использования хеша ui.

Marionette.ItemView.extend({
  ui: {
     'monkey': '.guybrush'
  },
  triggers: {
    'click @ui.monkey': 'see:LeChuck' // эквивалентно конструкции "click .guybrush"
  }
});

Триггеры работают во всех классах представлений (View), которые наследованы от базового класса Marionette.View.

Аргументы функции обработчика триггера

Функция обработчика события в триггере получает один аргумент, который включает в себя следующее:

  • представление
  • модель
  • коллекция

Эти свойства соответствуют свойствам view, model, и collection из представления, которое вызвало событие.

var MyView = Marionette.ItemView.extend({
  // ...

  triggers: {
    "click .do-something": "some:event"
  }
});

var myView = new MyView();

myView.on("some:event", function(args) {
  args.view; // => экземпляр представления, которое вызвало событие
  args.model; // => модель из представления - view.model, если модель была установлена в прдедставлении
  args.collection; // => коллекция из представления - view.collection, если коллекция была установлена в прдедставлении
});

Имея доступ к этим свойствам, позволяет обеспечить большую гибкость при обработке событий от множества представлений. Для примера, компонент управления вкладками или виджет для развернуть/свернуть бар-панель могут обрабытывать одинаковое событие от многих разных представлений, и обработка этого события будет описана в одной функции.

События модели в modelEvents и события коллекции в collectionEvents

Подобно хешу events, в представлениях можно указывать хеши для коллекций и моделей. С левой стороны указывается событие модели или коллекции, а с правой стороны имя метода из представления, который будет методом обратного вызова.

Marionette.CompositeView.extend({
  modelEvents: {
    "change:name": "nameChanged" // эквивалентно - view.listenTo(view.model, "change:name", view.nameChanged, view)
  },

  collectionEvents: {
    "add": "itemAdded" // эквивалентно - view.listenTo(view.collection, "add", view.itemAdded, view)
  },

  // ... методы обработчики событий
  nameChanged: function(){ /* ... */ },
  itemAdded: function(){ /* ... */ },
})

Эти конструкции используют памяти-безопасный listenTo и будет установлен контекст (значение this) в обработчике события, равный текущему представлению. События связываются во время создания экзепляра представления, и будет сгенерировано исключение, если функции-обработчики событий будут отсутствовать в представлении.

События из modelEvents и collectionEvents будут подключены и отключены от прослушивания при помощи вызова методов из Backbone.View: delegateEvents и undelegateEvents. Это позволяет представлению повторно использовать события для модели и коллекции при переподключении прослушивания событий.

Несколько функций обратного вызова

Для определения нескольких функций обратного вызова для события можно указать их друг за другом, разделяя их между собой пробелом.

Marionette.CompositeView.extend({
  modelEvents: {
    "change:name": "nameChanged thatThing"
  },

  nameChanged: function() {},

  thatThing: function() {},
});

Это работает для обоих modelEvents и collectionEvents.

Определение функций обратного вызова через функции

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

Marionette.CompositeView.extend({
  modelEvents: {
    "change:name": function() {
      // обработка события изменения имени будет здесь
    }
  }
});

Это работает для обоих modelEvents и collectionEvents.

Определение событий через функцию

Функция может быть использована для определения назначаемых событий. Эта функция должна возвращать хеш, который должен соответствовать виду указанному выше, т.е. иметь корректные вышеуказаные параметры.

Marionette.CompositeView.extend({
  modelEvents: function() {
    return { "change:name": "someFunc" };
  }
});

Это работает для обоих modelEvents и collectionEvents.

Метод serializeModel

Метод serializeModel сериализует модель, которая была передана аргументом.

Метод bindUIElements

В некоторых случаях возникает задача получить доступ к ui элементам внутри представления для того, чтобы получить у них данные или для манипуляции над ними. Для примера, у вас есть div элемент и вы хотите показать/скрыть его, основываясь на некотором состоянии или на состоянии другого ui элемента, которому вы хотите установить css-класс. Вместо того, чтобы использовать jQuery-селекторы, описываемые везде в коде представления, вы можете определить ui хэш, который сопоставляет название ui элемента с его jQuery-селектором. После этого вы можете получить доступ к ui элементу через this.ui.elementName. Для примера можно посмотреть документацию для ItemView

Эта функциональность для ui хэша обеспечивается через метод bindUIElements. Поскольку View не реализует метод render, то если вы напрямую наследуетесь от View, вам необходимо вызвать этот метод из вашего render метода. В ItemView и CompositeView об этом уже позаботились.

View.mergeOptions

Предпочтительным способом управления свойствами в Вашем представлении является метод mergeOptions. Он принимает 2 аргумента: options - объект и массив ключей. По этим ключам будут выбираться свойства из options и напрямую соединяться с представлением.

var ProfileView = Marionette.ItemView.extend({
  profileViewOptions: ['user', 'age'],

  initialize: function(options) {
    this.mergeOptions(options, this.profileViewOptions);

    console.log('The merged options are:', this.user, this.age);
  }
});

Подробнее mergeOptions

Метод getOption

Получает атрибут объекта напрямую у объекта или через this.options объекта, значение в this.options приоритетнее.

Больше информации о getOption

Метод bindEntityEvents

Помогает привязать backbone-скую сущность к методам целевого объекта. Метод bindEntityEvents используется для поддержки modelEvents и collectionEvents.

Больше информации о bindEntityEvents

Помощники в templateHelpers

Иногда, шаблону представления требуется некоторая логика при отрисовки данных, но сами движки генерации HTML могут не предоставлять простого пути для добавления этой специальной логики. Например, шаблоны Underscore не предоставляют механизма методов помощников, а шаблоны Handlebars предоставляют.

Атрибут templateHelpers может быть применен в любом объекте View, который отображает шаблон. Когда этот атрибут присутствует, его содержимое будет подмешано к данным, которые приходят от метода serializeData. Это позволяет вам создать методы помощники, которые можно вызывать внутри шаблона. Также это хорошее место для добавления данных, которые не возвращаются методом serializeData, например, рассчитываемые значения.

Типичный пример

<script id="my-template" type="text/html">
  I <%= percent %>% think that <%= showMessage() %>
</script>
var MyView = Marionette.ItemView.extend({
  template: "#my-template",

  templateHelpers: function() {
    return {
      showMessage: function() {
        return this.name + " is the coolest!";
      },

      percent: this.model.get('decimal') * 100
    };
  }
});

var model = new Backbone.Model({
  name: "Backbone.Marionette",
  decimal: 1
});

var myView = new MyView({
  model: model
});

myView.render(); //=> "I 100% think that Backbone.Marionette is the coolest!";

Атрибут templateHelpers может быть передан как параметр в конструктор любого Marionette-класса, который поддерживает помощников.

var MyView = Marionette.ItemView.extend({
  // ...
});

new MyView({
  templateHelpers: {
    doFoo: function() { /* ... */ }
  }
});

Доступ к данным в помощниках

В методах помощниках вы можете получить доступ к данным, для этого нужные данные вызываются с префиксом this. Через this вам доступны все методы и атрибуты сериализованного объекта данных, а также и другие методы помощники.

templateHelpers: {
  something: function() {
    return "Do stuff with " + this.name + " because it's awesome.";
  }
}

Определение templateHelpers через объект или функцию

В качестве templateHelpers вы можете указать литерал объект (как показано выше), ссылку на литерал объект или функцию.

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

Marionette.ItemView.extend({
  templateHelpers: function() {
    return {
      foo: function(){ /* ... */ }
    }
  }
});

Изменение шаблона (Template), который отображается (Rendered) в представления (View)

Иногда возникают случаи, когда вам нужно изменить шаблон (template), который используется в представлении, основываясь на некоторой простой логике, такой как некоторое значение определенного атрибута у модели представления. Для того, что бы это сделать, вы можете воспользоваться функцией getTemplate у вашего представления и использовать ее для возвращения нужного вам шаблона.

var MyView = Marionette.ItemView.extend({
  getTemplate: function() {
    if (this.model.get("foo")) {
      return "#some-template";
    } else {
      return "#a-different-template";
    }
  }
});

Все описанное в этом документе, относится ко всем классам представлений.

UI интерполяция

Marionette ui предлагает синтаксис, по которому можно ссылаться на элементы jQuery. ui элементы могут вставляться в события или селекторы регионов.

В примере ниже, кнопку buyButton используется в DOM событии, а checkoutSection - как селектор региона.

Marionette UI offers a convenient way to reference jQuery elements. UI elements can also be interpolated into event and region selectors.

In this example, the buy button is referenced in a DOM event and the checkout section is referenced in the region selector.

var MyView = Marionette.ItemView.extend({

  ui: {
    buyButton: '.buy-button',
    checkoutSection: '.checkout-section'
  },

  events: {
    'click @ui.buyButton': 'onClickBuyButton'
  },

  regions: {
    checkoutSection: '@ui.checkoutSection'
  },

  onShow: function() {
    this.getRegion('checkoutSection').show(new CheckoutSection({
      model: this.checkoutModel
    }));
  }
});