Динамическое отображение контролов
Большая часть сервисов СБИС используют серверную вёрстку. То есть при открытии веб-страницы на клиент приходят готовая HTML-разметка и список зависимостей, которые необходимы для "оживления" страницы и отображения стилей. Благодаря этому вёрстка не "прыгает", потому что отображение страницы происходит после загрузки стилей, и сами процессы загрузки исходников и "оживления" страницы происходят быстрее, потому что они не прерывают друг друга: сначала загружаются все необходимые исходники, а потом начинается "оживление".
Список загружаемых исходников собирается путём обхода по дереву зависимостей, корнем которого является самый верхний контрол (тот, у которого в шаблоне описан контрол Controls/Application).
Бывают ситуации, когда в это дерево не попадают зависимости, которые необходимы для построения веб-страницы. Например, инициализируемый список модулей зависит от данных, которые придут с бизнес-логики. Если загружать такие зависимости "на лету" (при "оживлении" на клиенте), то процесс "оживления" будет идти значительно дольше из-за прерываний на загрузку. Если же грузить на клиенте все возможные зависимости, то получится лишний трафик.
Для решения задачи сбора зависимостей контролов, динамически появляющихся на странице, был разработан контрол Controls/Container/Async (далее по тексту Async
). После построения на сервере, когда все запросы на бизнес-логику (далее по тексту "БЛ") отработают, и вёрстка полностью построится, становится известно какие модули будут необходимы для построения страницы на клиенте.
Компоненты, которые вставляются в шаблоне через Async
, и все их зависимости (включая CSS) добавятся в список зависимостей, необходимых для "оживления" страницы на клиенте. То есть, на момент отображения вёрстки и "оживления" страницы все необходимые CSS и JS файлы уже будет загружены.
Для того чтобы Async
подгрузил контролы, не указанные явно в зависимостях, необходимо передать название этого контрола в опцию templateName. Async
работает как обычный компонент высшего порядка, то есть ему можно передавать контент, который вставляется в шаблоне Async
'а через ws:partial), а templateOptions передаются как scope
в этот ws:partial
. Если content не указан, то Async
в опцию template
ws:partial
'а (внутри своего шаблона) передает templateName
.
Примеры
Простой пример использования контрола Async
:
<Controls.Container.Async templateName="MyModule/Test">
<ws:partial template="{{ content.resolvedTemplate }}" />
</Controls.Container.Async>
В опцию template
тега ws:partial
в контенте Async
'а нужно передавать content.resolvedTemplate
, а не строчку с именем модуля, иначе во время построения контента шаблонизатору необходимо будет еще раз по имени модуля находить сам модуль. В content.resolvedTemplate
уже будет лежать необходимая функция.
Такое использование актуально, например, если контрол вставлен под условием:
<ws:if data="{{ someCondition }}">
<Controls.Container.Async templateName="MyModule/Test">
<ws:partial template="{{ content.resolvedTemplate }}" />
</Controls.Container.Async>
</ws:if>
Таким образом, MyModule/Test
попадет в зависимости в итоговой html-страничке только в том случае, если условие someCondition
будет выполняться.
Также контрол Async можно использовать внутри тега <ws:for>
, если, например, вы пробегаетесь по списку модулей, который приходит с БЛ:
<ws:for data="key, value in data">
<Controls.Container.Async templateName="{{ value }}" templateOptions="{{ templateOptions }}">
<div>
<ws:partial template="{{ content.resolvedTemplate }}"></ws:partial>
</div>
</Controls.Container.Async>
</ws:for>
Пример использования с указанием content
и без указания:
<!--Без указания контента-->
<Controls.Container.Async templateName="template1" templateOptions="{{ itemOptions }}">
</Controls.Container.Async>
<!--С указанием контента-->
<Controls.Container.Async templateName="template2">
<ws:partial template="{{ content.resolvedTemplate }}" on:click="handler()"></ws:partial>
</Controls.Container.Async>
Использование контрола Controls/Container/Async
с указанием контента целесообразно только для подписки на события контента Async
. Все опции следует передавать в опцию templateOptions
у контрола Async
. При изменении опций контента необходимо отдавать в templateOptions
новый объект. В случае передачи опций на ws:partial
возникнет проблема при обновлении контента Async
. Так как опции, переданные на partial, обновятся в первом же цикле синхронизации, а контент Async
, если он еще не был загружен, обновится в одном из следующий циклов синхронизации. Таким образом возникнет ситуация, когда в старый контент будут переданы новые опции.
Внутри описания контента Async
в опцию template
нужно передавать content.resolvedTemplate
. Эта опция передается в шаблоне Async
в partial
, в котором вставляется контент. Если в ws:partial
в template
передать константную строчку, то она попадет в дерево зависимостей, в зависимости шаблона, и всегда будет прилетать в зависимостях на клиент.
Еще пример использования:
<ws:if data="{{ item.type === 'Collage' }}">
<Controls.Container.Async templateName="templates/Collage"/>
</ws:if>
<ws:if data="{{ item.type === 'Vote' }}">
<Controls.Container.Async templateName="templates/Vote"/>
</ws:if>
<ws:if data="{{ item.type === 'Simple' }}">
<Controls.Container.Async templateName="templates/Simple"/>
</ws:if>
Так может выглядеть itemTemplate
для полиморфного списка новостей, написанный с использованием контрола Async
.
При отключенной серверной верстке, участок интерфейса, который вставляется в шаблоне через Async
подгрузится динамически. То есть исходники всех необходимых контролов, включая css, будут загружены в _beforeMount
Async
'а.