Разработка контролов

Hello world

На Wasaby можно достаточно быстро и легко научиться разрабатывать, потому что наш фреймворк строится на базовых принципах HTML, CSS и JavaScript. Посмотрите на демо-пример на CodeSandbox

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

Файловая структура примера:

  • Demo — папка с исходными файлами контрола;
    • Template.wml — шаблон контрола;
    • Module.ts — модуль контрола;
  • index.html — тестовая веб-страница, на которую подключено ядро Wasaby (wasaby.min.js).

Инициализация контрола и его вставка на страницу выполнена следующим скриптом:

<!-- WML -->
<script>
   require(["UI/Base:Control", "Demo/Module"], function(Control, Module) {
      Control.createControl(Module, {
         element: document.querySelector("#mainContainer")
      }, element);
   });
</script>

Декларативное отображение

Чтобы отобразить данные на странице, достаточно указать в каком месте шаблона их следует поместить.

<!-- WML -->
<div title="{{ text }}">
   {{ text }}
</div>
// TypeScript
import { Control, TemplateFunction } from 'UI/Base';
import * as template from 'wml!Demo/Template';

export default class extends Control {
     protected _template: TemplateFunction = template;
     text: "Hello Wasaby!";
}

Результат. При наведении курсора на строку отобразится подсказка.

Hello Wasaby!

См. демо-пример на CodeSandbox

Как видно из примера, данные можно вставлять в содержимое тега и в его атрибуты. Более того, теперь они реактивно связаны с DOM. Как это проверить? Откройте страничку демо-примера в отдельной вкладке. Затем выполните в консоли разработчика следующий код:

document.querySelector('#mainContainer').controlNodes[0].control.text = 'Hello world!'

Так мы изменяем значение переменной text, и оно сразу автоматически обновляется на странице.

Условия и циклы

Для управления присутствием элемента в DOM мы используем директиву <ws:if>, что продемонстрировано в следующем примере.

<!-- WML -->
<div>
   <ws:if data="{{ isVisible }}">
      Message is visible.
   </ws:if>
   <ws:else>
      Message is hidden.
   </ws:else>
</div>
// TypeScript
import { Control, TemplateFunction } from 'UI/Base';
import * as template from 'wml!Demo/Template';

export default class extends Control {
     protected _template: TemplateFunction = template;
     isVisible: true;
}

Результат:

Message is visible.

См. демо-пример на CodeSandbox

Для многократного добавления элемента мы используем директиву <ws:for>, как это показано в примере ниже.

<!-- WML -->
<ul>
    <ws:for data="key, value in list">
        <li>{{ value }}</li>
    </ws:for>
</ul>
// TypeScript
import { Control, TemplateFunction } from 'UI/Base';
import * as template from 'wml!Demo/Template';

export default class extends Control {
     protected _template: TemplateFunction = template;
     list: null;

    protected _beforeMount(): void {
        this.list = ["Messages", "Chats", "Groups"];
    }
}

Результат:

* Messages
* Chats
* Groups

См. демо-пример на CodeSandbox

В примере мы впервые использовали метод _beforeMount(), где объявили переменную. А последующих разделах мы подробнее поговорим о назначении метода.

Обработка событий

Для создания интерактивных приложений мы можем реагировать на действия пользователя, например, клик по кнопке. В следующем примере показано, как мы можем отследить и обработать событие click для DOM элемента.

В следующем примере в обработчике описана только логика обработки, а сама работа с DOM выполняется автоматически ядром Wasaby.

<!-- WML -->
<div>
    Counter: <button on:click="clickHandler()">{{ count }}</button>
</div>
// TypeScript
import { Control, TemplateFunction } from 'UI/Base';
import * as template from 'wml!Demo/Template';

export default class extends Control {
     protected _template: TemplateFunction = template;
     count: 0;

    clickHandler(): void {
        this.count++;
    }
}

Результат: мы создали простой счетчик, подсчитывающий количество нажатия на кнопку.

См. демо-пример на CodeSandbox

В следующем примере показана обработка пользовательского ввода.

<!-- WML -->
<div>
    <p>Input your name: <input type="text" on:input="inputHandler()"/></p>
    <p>Your name is {{ name }}</p>
</div>
// TypeScript
import { Control, TemplateFunction } from 'UI/Base';
import * as template from 'wml!Demo/Template';

export default class extends Control {
     protected _template: TemplateFunction = template;
    inputHandler(event): void {
        this.name = event.target.value;
    }
}

Результат: когда пользователь вводит символ в поле ввода, они сразу же отображаются в строке ниже.

См. демо-пример на CodeSandbox

Приложение как набор контролов

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

Контрол — это изолированная часть функционала. С точки зрения файловой структуры, это минимум два файла: JS-модуль, где описана логика, и WML-шаблон, где описано представление контрола.

Ниже показан пример контрола-спойлера:

<!-- WML -->
<div>
    <button on:click="clickHandler()">show more</button>
    <ws:if data="{{ showSpoiler }}">
        <p style="border: 1px solid #ccc">{{ _options.description }}</p>
    </ws:if>
</div>
// TypeScript
import { Control, TemplateFunction } from 'UI/Base';
import * as template from 'wml!Demo/Template';

export default class extends Control {
     protected _template: TemplateFunction = template;
    showSpoiler: false;

    clickHandler(): void {
        this.showSpoiler = !this.showSpoiler;
    }
}

Теперь его можно переиспользовать в другом контроле. Давайте сделаем это:

<!-- WML -->
<div>
    Click on the button to display additional text.
    <Spoiler.Module description="{{ text }}" />
</div>
// TypeScript
import { Control, TemplateFunction } from 'UI/Base';
import * as template from 'wml!Demo/Template';

export default class extends Control {
     protected _template: TemplateFunction = template;
     text: "This text was hidden by spoiler, but now it is visible. You can click again to hide this text.";
}

См. демо-пример на CodeSandbox

В примере показано, что родительский контрол Demo/Module передаёт данные в дочерний контрол-спойлер.

Узнать больше

Выше мы кратко представили основные возможности Wasaby Framework. Подробнее о разработке контролов вы можете прочитать в разделах: