Вступление
Вчера меня снова потянуло на ExtJS. Видимо, жарища так влияет. Поковырявшись в интернете, я нашел черновую версию книги ExtJS in Action, загрузил ее в свой Sony Reader и стал читать. После прочтения трех первых глав пришло осознание того, насколько красиво там сделаны некоторые базовые вещи. В этой статейке я остановлюсь на двух моментах.1. Config-объекты и xtypes
В ExtJS, если существует компонент, например,MyComponent
, то у него обязательно есть родственник MyComponentConfig
. Последний содержит все настройки компонента. И возможны два случая.Либо он передается в конструктор
MyComponent
-у, и экземпляр MyCompoment
создается немедленно. В этом случае такой объект называется config object.Либо он содержится в коллекции элементов (родительского) контейнера. Тогда контейнер создаст компонент на основе конфигурации, когда в этом будет необходимость. В этом случае
MyComponentConfig
называют xtype.Так как ExtJS – это Javascript библиотека, а Javascript – язык с нестрогой типизацией, то
MyComponentConfig
как такового нету. Вместо него используются Javascript plain objects с полем xtype
.Рассмотрим пример. Мы хотим создать textbox. Вот его настройки:
var fieldConfig = {
xtype: 'textfield',
fieldLabel: 'Your name',
value: 'test'
};
Теперь можно создать textbox явно:var field = new Ext.form.TextField(fieldConfig);
field.render(document.body);
А можно создать форму с текстбоксом вот так:var form = new Ext.form.FormPanel({
items: [ fieldConfig ]
});
form.render(document.body);
Во втором случае есть контейнер (FormPanel
), и конфигурация текстбокса находится в коллекции items
. Как видно, текстбокс никто не создает – его создаст контейнер.Вроде бы ничего особенного, но смотрите, что дает нам эта схема:
a) Возможность комбинировать компоненты без каких либо ограничений
Опишу ситуацию на примере, который недавно наблюдал на работе. Допустим вы разработали некийBlazingFastControl
. Он достаточно навороченный, у него 100 опций по управлению наворотами:Прошло время. Надо развивать продукт, и вы решили написать вот такое:
Объединив
BlazingFastControl
и MegaDropDown
, хотите получить некий BlazingFastLookup
.Но вот беда: надо дать пользователю возможность как-то настраивать внутренний компонент. И если настройки не были изолированы в отдельный объект
BlazingFastConfig
, то придется дублировать все 100 опций и писать глупый код по их копированию. Особенное зло ждет в .NET, где каждая property обычно обвешана десятком атрибутов.b) Config-driven component assembly
По-русски это значит, что config-объекты – это готовый способ сериализации UI. То есть весь интерфейс или его куски можно описывать и хранить в JSON или в другом формате.Вы скажете мол ничего удивительного – ASP.NET контролы тоже можно объявлять в разметке. Но есть нюанс:
c) Отложенное создание вложенных компонентов
Представьте себе следующий UI: tab-panel в тремя вкладками, и за каждой вкладкой скрывается целый мир компонентов.Если это описать в виде config-объектов, то после запуска не будет нужды создавать тяжелые экземпляры всех компонентов. Достаточно будет создать только то, что видно на активной вкладке. А на остальные, может быть, никто и не переключится, и 2/3 компонентов не будут даже создаваться, а так и останутся в зачаточном состоянии. Это – большая экономия ресурсов!
Почитать еще можно на stackoverflow.
2. Layouts
В ExtJS есть контейнеры (Container), которые содержат элементы (items). То, как элементы будут отображаться внутри контейнера, диктует специальный объект Layout.Объясню на абстрактном примере. Объявим контейнер и элемент так:
class Container {
public Collection<IItem> Items { get; }
public ILayout Layout { get; }
}
interface IItem {
string Text { get; }
}
Допустим, наше приложение имеет дело с документами:class MyDocument : IItem {
public string Title { get; set; }
public string Content { get; set; }
// ...
string IItem.Text { get { return Title; } }
}
Можно создать Container
, заполнить его MyDocument
-ами. И с помощью разных реализаций ILayout
получить меню, табы, nav bar, форму или что-то свое невообразимое.