События на DOM элементе и конструкция runtime вывода.

Работа с событиями

Для привязки и работы с DOM событиями в режиме runtime, фреймворк имеет собственный набор функций (fcf.addDomListener(), fcf.removeDomListener(), fcf.emitDomEvent()). Которые облегчают работу с DOM событиями. В частности, снимает необходимость отвязки события от враппера при его разрушении и перерисовке.

Для примера применения данного функционала мы сформируем две фичи.

Добавим к нашему приложению эффект, при котором при клике по движущейся строке порядок символов будет инвертирован. Это мы реализуем при помощи функции fcf.addDomListener().

Файл :templates/blocks/moving-containers+view-item.wrapper.js

... attach(){ this.setPosition(); this.setColor(); fcf.addDomListener(this.getDomElement(), "click", this); return super.attach(); } onClick(a_event){ let string = this.getArg("string"); string = string.split("").reverse().join(""); this.setArg("string", string); } ...

Код достаточно прост. При каждом обновлении шаблона мы выполняем привязку обработчика события click. Обратите внимание, что данный подход используется при установленной опции шаблона merge в значение true. При повторной привязке для одного владельца обработчика события, происходит просто замещение обработчика события, а не его добавление.

Теперь взглянем на результат. Как видно все работает достаточно просто.

Второй фичей будет подсчет количества отскоков строк от краев контейнера. На базе данной фичи мы применим вызов DOM события.

При каждом отскоке от границы контейнера элемент view-item будет отправлять кастомное событие rebound, вызовом функции fcf.emitDomEvent().

Файл :templates/blocks/moving-containers+view-item.wrapper.js

... setPosition(){ let selfRect = fcf.getRect(this.getDomElement()); let ownerRect = fcf.getRect(this.getParent().select(".moving-containers-view")[0]); let dx = Math.cos(this._radians) / 200; let dy = Math.sin(this._radians) / 200; if ((dx > 0 && (this._x + (selfRect.width / ownerRect.width) + dx > 1)) || (dx < 0 && (this._x + dx < 0))) { this._radians += ((Math.PI / 2) - this._radians) * 2; dx = -dx; fcf.emitDomEvent(this.getDomElement(), "rebound", {}); } else if (((dy > 0) && (this._y + (selfRect.height / ownerRect.height) + dy > 1)) || ((dy < 0) && (this._y + dy < 0))){ this._radians += (Math.PI - this._radians) * 2; dy = -dy; fcf.emitDomEvent(this.getDomElement(), "rebound", {}); } this._x += dx; this._y += dy; let rect = fcf.getRect(this.getParent().select(".moving-containers-view")[0]); this.getDomElement().style.left = (this._x * rect.width + rect.left) + "px"; this.getDomElement().style.top = (this._y * rect.height + rect.top) + "px"; } ...

В коде основного шаблона выведем HTML элемент с количеством отскоков и добавим обработчик нашего нового события rebound к подшаблону view-item, но для этого нам с начала нужуно ознакомится с конструкцией вывода конструкцией runtime вывода.

Конструкция runtime вывода #{{}}#.

Помимо конструкции вывода @{{}}@, фреймворк поддерживает runtime конструкцию вывода #{{}}#. Данная конструкция выполняет автоматическое обновление выведенного фрагмента без обновления шаблона при обновлении аргумента в автоматическом режиме. Однако, ввиду того что фреймворку приходится работать непосредственно с DOM элементами, конструкция #{{}}# имеет ограничения на использования и может быть использована, либо в качестве выводимого контента, либо в виде атрибутов DOM элемента. Так же в конструкции runtime вывода не доступен объект render (Но это может быть будет исправлено, если фреймворк будет успешно развиваться).

Добавим аргумент шаблона "_reboundCounter", который будет хранить количество отскоков и выведем его занчение используя конструкцию #{{}}#. Значение "_reboundCounter" будет увеличиваться на единицу при каждом вызове обработчика события  "rebound" подшаблона "view-item"

Файл :templates/blocks/moving-containers.tmpl

... //~ARGUMENTS { _strings: fcf.argProg(), _file: fcf.argVal("/files/background.jpg?dump=@{{fcf.id()}}@"), _reboundCounter: 0 } //~TEMPLATE <div class="moving-containers-view" style="background-image: url(@{{args._file}}@);"> <div class="moving-containers-view-info"> Rebound counter: <span name="rebound_counter">#{{args._reboundCounter}}#</span> </div> %{{ for(let i = 0; i < args._strings.length; ++i) { }}% @{{ render.template( "+view-item", { string: fcf.argRef(`_strings[${i}]`), fcfEventRebound: "parent.setArg('_reboundCounter', parent.getArg('_reboundCounter')+1)" })}}@ %{{ } }}% </div> ...

И посмотрим результат.