Skip to content

Widgets

Pavel Motorin edited this page Jun 27, 2013 · 10 revisions

Widgets module

Для подключения js-виджетов, которые должны работать только в рамках какого-то блока, нужно использовать атрибут data-js-widgets="...". При желании, можно указать несколько таких виджетов через запятую.

<section data-reload-sections="…">
    <div data-js-widgets="/js/some_widget1.js, /js/some_widget2.js"></div>
    <div></div>
</section>

Этот атрибут можно указать у любого DOM-элемента. При инициализации виджета этот элемент будет передан ему соответствующим параметром.

Structure

Виджеты пишутся по стандарту AMD. Определяющая функция должна возвращать объект, который расширяет базовый интерфейс.

Пример минимально достаточного виджета:

define([], function(){
    return {}
});

API

define([], function(){
    return {
        domEvents: 
            // (см. ниже domEvents)
        },
        moduleEvents: {
            // (см. ниже moduleEvents)
        },
        init: function(){
            // Опциональная функция. Вызывается в самом начале, если определена.
            // Поле @element является ссылкой на DOM-элемент, к которому
            // этот виджет был подключен
        },
        turnOn: function(){
            // Optional function.
            // Вызывает в ситуации, когда виджет «включается». 
        },
        turnOff: function(){
            // Optional function.
            // Вызывается в ситуации, когда виджет «выключается». 
            // Используется очень редко. Имеет смысл использовать 
            // Только для отписки от событий, которые были навешены
            // вручную внутри turnOn()
        }
    }
});

Для более аккуратной работы с памятью и для предотвращения лишних утечек рекомендуется использовать соответствующие поля — domEvents и moduleEvents.

@element

Внутри инстанцированного виджета доступна переменная @element, которая является ссылкой на корневой DOM-элемент, в рамках которого инстанцирован виджет. (к которому этот виджет был подключен).

Поле domEvents

Используется для подписки на DOM-события, которые могут случиться на child-элементах виджета. Например:

domEvents: {
  "click #someId": "callbackName",
  "click #someSecondId": someFunction,
  "click #someThirdId": function(evt, element){ … }
  "click @element": "secondCallbackName"
}
callbackName: function(evt, targetEl) {
    // evt — стандартный объект события
    // evt.target - DOM-node, на которой произошло событие (клик мышкой)
    // targetEl — тот элемент, на который была оформлена подписка. 
    // this — контекст объекта самого виджета (важно!)
}
    

Обратите внимание, что someFunction, также как и анонимная функция вызовутся тоже в контексте этого виджета. targetEl введен специально для ситуаций, когда вы повесили обработчик на общий контейнер, а внутри, например есть картинка — тогда браузер изначально в event событии будет считать, что evt.target — это картинка. Тем не менее targetEl будет тем самым нужным контейнером.

Напомним, что @element — это корневой DOM-элемент, на котором инстанцирован виджет.

Поле moduleEvents

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

moduleEvents: 
    "someCustomEventName": "callbackName"
    "anotherEventName": {
        handler: "anotherCallback",
        isSync: false,
        recall: false,
     }
}
callbackName: function(data){
   // data — сопроводительные данные, если таковые были в момент генерации события
}

Также есть возможность использовать дополнительные параметры подписки, которые свойственны модулю events. В таком случае надо указывать объект, где имя хендлера передается в поле handler.

isSync — означает, что хендлер надо вызвать синхронно. По умолчанию false.

recall — если true и такое событие уже случалось раньше, до момента инициализации виджета, то сразу же вызывает handler с данными последнего случая события. По умолчанию false.

Методы turnOn() и turnOff()

Optional functions. Используются очень редко.

turnOn() — для навешивания событий, которые никак нельзя навесить через domEvents и moduleEvents. Вызывается автоматически при первой инициализации и в моменты «включения» виджета — например, когда пользователь идет назад по истории.

turnOff() — для отписки от таких «ручных» событий. Вызывается в моменты «выключения» виджета. Например, когда DOM-элемент, к которому приписан виджет, изымается из DOM дерева.

Например: window.onscroll, window.onresize или что-то еще подобное.

Тем не менее, если есть возможность всю работу, например, с window.onscroll вынести в отдельный модуль, который будет триггерить нужные события через events (см. ниже), то лучше это сделать.

turnOn: function() {
    $(window).on("scroll.myWidget", $.proxy(@_onScroll, @))
},
turnOff: function() {
    $(window).off("scroll.myWidget")
},
_onScroll: function(evt) {
    // … some actions on scrolling …
}

Полезное

Создание событий для других виджетов

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

define(["events"], function(events){
    init: function(){
    
        events.trigger("my-widget-event", [customData1, customData2, ...])
    }
});

В таком случае, в другом виджете (или, если угодно, в том же самом ;) подписка будет выглядеть таким образом:

define([], function(events){
    moduleEvents: {
        "my-widget-event": "myWidgetEventCallback"
    }
    myWidgetEventCallback: function(data){
       // data = [customData1, customData2, …]
    }
    init: function(){    
       // ...
    }
});