Архитектура клиентского приложения на ExtJS. Часть 1

Библиотека ExtJS/Sencha
ExtJS
Самое сложное в любой работе — это начать её. Итак, с чего же начать наше огромное клиентское приложение? В этой части я расскажу с чего начать и затрону три темы: Как организовать код, Что такое фасад, как его построить, что такое компоненты (и, конечно, как их начать писать).

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

Начало


Я бы предложил создать иерархию директорий в вашей папке с яваскриптами. Предположим, эта папка зовётся js. Тогда рекомендуемая мною иерархия директорий будет следующей:
  • ext
  • js
    • components
    • plugins
    • resources
    • ...

Папка ext содержит сам фреймворк, а js — файлы, внешние по отношению к фреймворку. В /js будет храниться единственный файл, который будет являться фасадом нашего приложения. В /js/components будут находиться все ваши наследники компонентов, о которых мы позже поговорим в деталях, в /js/plugins будут находиться плагины, т.е. компоненты, входящие в коллекцию plugins некоторых других компонентов. О плагинах я также расскажу немного позже. И, наконец, /js/resources в котором вы можете хранить файлы ресурсов со статическими переменными, различными вспомогательными функциями, переопределениями объектов и т.д. и пр.

Далее, на нашей страничке с приложением (скажем, index.html) организовываем в шапке наши скрипты таким образом:
  1. файлы /ext
  2. ресурсы из /js/resources
  3. плагины из /js/plugins
  4. модули-компоненты из /js/components
  5. фасад из /js

Почему именно в этом порядке? Потому, что такова наша иерархия зависимостей. Фреймворк от наших скриптов не зависит и от того стоит первым. Ресурсы могут зависеть лишь от объектов и функций из фреймворка, плагины используют ресурсы и фреймворк, модули-компоненты используют плагины, ресурсы и фреймворк, а фасад использует всё выше него. На то он и фасад.

Таким образом, мы решили проблему зависимости, которая у меня несколько раз вставала из-за неверного расположения компонентов.

Управление зависимостями в яваскрипте — вообще отдельная тема, но если вам интересно, советую обратить внимание на Jingo. Я с этой библиотекой познакомился совсем недавно и, как мне показалось, при её использовании слишком многое пришлось бы менять в существующем, уже отлаженом коде. Но проблему зависимостей эта библиотека решает весьма изящно.

Фасад



Дальше стоит написать каркас фасада. Что он из себя представляет? А представляет он из себя обычную функцию, которая в итоге монтируется к Ext.onReady (т.е. фасад начинает «жить» после того, как дом-модель нашей индексной странички будет построена). Вот пример фасада:

Copy Source | Copy HTML
  1. /**<br/> * filename: facade.js<br/> * description: Application Layout<br/> */
  2. Ext.namespace("Layout");
  3. Layout.base = function(){
  4. // Всплывающие подсказки необходимо инициализировать
  5. Ext.QuickTips.init();
  6. // Далее мы определяем разные функции и объекты, которые будут
  7. // использованы напрямую или косвенно во Viewport
  8. // ...
  9. return {
  10. init: function(){
  11. new Ext.Viewport({/* конфигурация рабочей области, подключение модулей */});
  12. }
  13. };
  14. }();
  15. Ext.onReady(Layout.base.init, Layout.base);


Компоненты



Во Viewport, в фасаде мы подключили наши панели и навигацию. Теперь пора наладить базовое взаимодействие элементов меню с областью содержимого во Viewport. Предположим, вашей целью является смена содержимого по нажатию на элементы меню. У вас есть элемент «Отчёты» и элемент «Настройки» в вашем меню и вы хотите видеть в области содержимого, при нажатии на эти пункты меню, соответственно, содержимое, соответствующее отчётам и содержимое, соответствующее настройкам. Для этого вы в коллекцию items в панели, отвечающей за содержимое, помещаете компонент отчёта или компонент настроек (ситуация может немного варьироваться в зависимости от того, какой layout вы применили в области контента).

Итак. В данной статье я буду придерживаться соглашения о том, что компоненты — это наследники визуальных компонентов в Ext. Вам практически всегда необходимо будет иметь, как минимум, переопределённые стандартные визуальные компоненты. В различных туториалах по Ext такие компоненты называются preconfigured controls и представляют собой реализацию концепции наследования в ООП.

Вот так, если кратко, реализуются переопределения на примере GridPanel, выступающем в роли базового класса:
Copy Source | Copy HTML
  1. Ext.namespace("Application.Reports");
  2. Application.Reports.BaseReport = Ext.extend(Ext.grid.GridPanel, {
  3. constructor: function(config){
  4. // Нам очень редко придётся использовать сам конструктор, так что этот метод можно и вовсе
  5. // опустить, если мы не хотим сделать что-то с конфигурацией ещё до того, как она попадёт
  6. // в базовый конструктор. Но иметь представление о том, что функция конструктора всё же есть - надо.
  7. // Нельзя забывать вызывать базовый метод, если таковой имеется
  8. Application.Reports.BaseReport.superclass.constructor.apply(this, arguments);
  9. }
  10. , initComponent: function(){
  11. // А вот этот метод очень важен. Инициализация компонента вызывается после конструктора.
  12. // А потому переопределённая конфигурация приоритетнее конфигурации, заданной пользователем
  13. // в конструкторе. В нём мы и будем переопределять конфигурацию объекта.
  14. // Копируем с заменой все свойства второго аргумента в первый. Что бы там пользователь
  15. // в конструкторе для свойств ни определил, если эти свойства будут во втором аргументе - они
  16. // заменят собой свойства в нашем объекте
  17. Ext.apply(this, {
  18. title: "Our Title"
  19. , loadMask: true
  20. /* Остальные свойства */
  21. , plugins: [
  22. // Пока не берите в голову, что такое Ext.ux.grid.MetaGrid.
  23. // RESOURCES.SETTINGS.RECORDS_PER_PAGE - это синглтон, определённый в файле ресурса, в /js/resources
  24. // RECORDS_PER_PAGE = значению 50.
  25. new Ext.ux.grid.MetaGrid({paging: {perPage: RESOURCES.SETTINGS.RECORDS_PER_PAGE}})
  26. ]
  27. });
  28. // Не забываем вызывать базовый метод инициализации
  29. Application.Reports.BaseReport.superclass.initComponent.apply(this, arguments);
  30. }
  31. });


На этом я пока закончу. В следующей части:
  • Немного об архитектуре компонентов
  • Плагины
  • Советы
Теги:ExtJSархитектура приложений
Хабы: Библиотека ExtJS/Sencha
+24
5,4k 105
Комментарии 28

Похожие публикации

Лучшие публикации за сутки