Использование маршрутизации Wasaby

В этой статье даны примеры создания страниц и настройки маршрутов.

Настройка маршрутизации для конкретных приложений СБИС, например online.sbis.ru, может иметь свои особенности. Поэтому перед началом работы рекомендуется обратить внимание на связанные с темой статьи:

Создание новой страницы

Страницей считается контрол с названием Index, который находится в корне интерфейсного модуля.

  1. Создадим новый интерфейсный модуль (например, Travel).
  2. Создадим в этом модуле контрол Index с шаблоном приложения.
// Travel/Index.ts
import * as Control from 'Core/Control';
import * as template from 'wml!Travel/Index';
 
export default class TravelPage extends Control {
    protected _template: Function = template;
}
<!-- Travel/Index.wml -->
<SbisEnvUI.Bootstrap>
    <div>
        <h1>Страница Travel!</h1>
    </div>
</SbisEnvUI.Bootstrap>

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

Создание новой страницы в приложении online.sbis.ru

На online.sbis.ru используется система маршрутизации, которая основана на сведениях из настоящей статьи. В ней используется собственный подход к созданию и конфигурации страниц. Подробнее об этом читайте в статье.

Сопоставление маршрутов

При переходе по URL-адресу определяется соответствующее ему приложение:

  1. Изменяется префикс URL-адреса согласно таблице замен router.json. Подробнее об этом файле будет сказано далее.
  2. Из получившегося адреса извлекается подстрока между первыми двумя слэшами. Она используется в качестве названия интерфейсного модуля.
  3. Данный URL-адрес соответствует приложению в контроле Index полученного интерфейсного модуля.

Таблица замен собирается из файлов router.json, которые могут содержаться в любом интерфейсном модуле. Она содержит информацию о том, как необходимо изменить URL-адрес перед поиском соответствующего ему приложения.

Файл router.json должен находиться в корне интерфейсного модуля и иметь следующий формат:

// router.json
{
   "префикс url": "замена префикса",
   "префикс url 2": "замена 2",
   ...
}

На первом шаге маршрутизации выполняется обход этого списка. В нем ищется самый длинный префикс, который совпадает с началом текущего URL-адреса. После завершения поиска, если такой префикс был найден, выполняется его замена в URL-адресе на соответствующую строку.

Это можно использовать например для того, чтобы сделать приложения доступными по адресам, отличным от названий их интерфейсного модуля. Например:

// router.json
{
   "Books": "BookShop",
   "Books/Bestselling": "ExpensiveShop/Books/Best",
   "Tickets": "TicketShop"
}

В этом примере при переходе по адресу /Books/ будет найден самый длинный подходящий префикс Books и совершен переход по адресу /BookShop/, то есть будет загружено приложение BookShop/Index.

При переходе по адресу /Books/Bestselling/2019 наиболее подходящий префикс — Books/Bestselling, поэтому будет совершен переход по адресу /ExpensiveShop/Books/Best/2019, и загружено приложение ExpensiveShop/Index.

Для адреса /Buy/Tickets в таблице префикса нет, поэтому он останется без изменений, и будет загружено приложение Buy/Index.

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

В router.json также может задаваться особая "корневая" замена с помощью префикса "/". Эта замена применяется только при переходе на корневой URL-адрес с возможностью наличия в адресе query-параметров, то есть параметров вида name=value.

Это можно применить, чтобы контрол Travel/Index из примера был доступен по корневому маршруту:

// router.json
{
   "/": "Travel"
}

При такой замене, по адресам /, /?promo=true и т.д. будет открываться приложение Travel/Index. При этом, по адресу /abc будет доступно уже приложение abc/Index.

Добавление адресов в файл router.json должно быть согласовано с ответственным за приложение. Для online.sbis.ru такое согласование должно быть с Новиковым Д.В.. Также для online.sbis.ru такая замена должна быть описана в конфигурации онлайн-роутинга.

Во время сборки файлы router.json из всех интерфейсных модулей объединяются в один, который представляет собой единую таблицу замен.

Вложенные маршруты

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

  1. Добавим на страницу список стран, при клике на которые их названия будут записываться в URL-адрес, с помощью контрола Router/router:Reference.
// Travel/Index.ts
...
export default class TravelPage extends Control {
    protected _template: TemplateFunction = template;
     
    // Добавляем список стран
    private _countries = {
        'russia': {
            name: 'Россия',
            cities: ['Москва', 'Санкт-Петербург', 'Новосибирск']
        },
        'italy': {
            name: 'Италия',
            cities: ['Рим', 'Милан', 'Неаполь']
        },
        'france': {
            name: 'Франция',
            cities: ['Париж', 'Марсель', 'Лион']
        }
    };
}
<!-- Travel/Index.wml -->
...
<h1>Страница Travel!</h1>
<div class="countries">
    <span class="countries__title">Выберите страну отправления:</span>
    <!-- Выводим ссылки на все страны списком -->
    <ul class="countries__list">
        <ws:for data="urlName, country in _countries">
            <li>
                <Router.router:Reference
                    state="country/:countryName"
                    countryName="{{ urlName }}">
                    <a href="{{ content.href }}">{{ country.name }}</a>
                </Router.router:Reference>
            </li>
        </ws:for>
    </ul>
</div>
...
  1. При клике на ссылки, в адресной строке браузера появится и будет изменяться параметр country/<название страны>. Для чтения параметров из URL-адреса используется контрол Router/router:Route. Используем его для отображения списка городов выбранной страны.
<!-- Travel/Index.wml -->
...
<div class="countries">...</div>
<Router.router:Route mask="country/:cName">
    <div class="cities">
        <!-- Отображаем города только если страна выбрана, и она есть в списке -->
        <ws:if data="{{ content.cName && _countries[content.cName] }}">
            <span class="cities__title">Города страны {{ _countries[content.cName].name }}:</span>
            <ul class="cities__list">
                <ws:for data="city in _countries[content.cName].cities">
                    <li>{{ city }}</li>
                </ws:for>
            </ul>
        </ws:if>
    </div>
</Router.router:Route>
...

Таким образом, выбор страны из списка стран приводит к изменению URL-адреса. При изменении адреса обновляется контрол Route, его шаблон перестраивается, на экране отображается новый список городов.

Так как контрол Route реагирует на любое изменение адреса, появляется поддержка кнопок вперед/назад браузера. Если кликнуть на ссылку "Россия", затем на ссылку "Франция", то при переходе по истории браузера, Route также будет обновляться и перерисовывать список городов.

Route работает на Сервисе представлений, что позволяет при переходе по адресу /Travel/country/italy сразу получить с сервера построенную верстку, включающую в себя список городов Италии.

Более подробное описание работы с контролами Route и Reference, а также инструкцию по запуску демо-примеров, можно найти в здесь.

Переход между приложениями

Переход с приложения Index одного интерфейсного модуля на Index другого может происходить без перезагрузки страницы. Такой переход происходит, если Router/router:Reference переадресует пользователя по такому адресу, для которого алгоритм сопоставления маршрутов вернет приложение, отличное от текущего.

  1. Создадим новый интерфейсный модуль Purchases, и добавим в него приложение Index.
<!-- Purchases/Index.wml -->
<SbisEnvUI.Bootstrap>
    <div>
        <h1>Страница Purchases</h1>
    </div>
</SbisEnvUI.Bootstrap>

Purchases/Index.ts должен экспортировать контрол, с установленным шаблоном Purchases/Index.wml. 2. На странице Travel/Index добавим ссылку, перенаправляющую на новую страницу.

<!-- Travel/Index.wml -->
...
<Router.router:Reference
    state="/Purchases">
    <a href="{{ content.href }}">Перейти к Purchases</a>
</Router.router:Reference>
...

При нажатии на эту ссылку, будет совершен переход к приложению Purchases/Index, оно будет загружено вместо текущего приложения Travel.

Если контрол Index из интерфейсного модуля, на который ссылается путь Reference, загрузить не удается, предполагается что этот адрес как-то обрабатывается на сервисе представлений, поэтому производится стандартный переход с перезагрузкой страницы.

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