Написание больших приложений на ExtJS (Часть1)

Предисловие

Я решил написать эту статью для тех пользователей Ext 2.x, которые уже выросли из приложений состоящих из одной HTML страницы со встроенным скриптом, который создает одно простое окно или форму, для тех, кто уже решили, что Ext это их выбор и для тех, кто борется со слишком большими файлами, где трудно что-то найти и тех, кто чувствует, что их приложения требуют структуры.

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

Я только хочу сказать, что мой подход, позволяет легко структурировать и писать красивый код. Он «реально работает»!

Что можно назвать большим приложением ?

Если у вас есть Viewport с BorderLayout, grid и формы — все в одном файле, это конечно, небольшое приложение. А вот если у вас десятки окон с формами, гридами и все это в 10 файлах, это уже не маленькое приложение, правда ?

(У немцев есть забавное выражение Jein, которое является производным от Ja = Да и Nein = Нет )

Ответ на вопрос поставленный выше это Jein (Прим. переводчика: Русское Да-нет наверное тоже является эквивалентом этого немецкого слова). Нет однозначного ответа, когда приложение становится большим, оно становится большим, когда вы считаете, что оно стало большим. Этот момент обычно наступает, когда вы уже не можете ориентироваться в ваших файлах, когда вы перестаете понимать как ваши компоненты в приложении соотносятся друг с другом. Нужно также представлять что будет, если с вашим кодом начнет работать программист в 2 -3 раза менее опытный чем вы.

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

Самое лучше — начинать писать приложение со словами: «Я начинаю писать большое приложение!».

Файлы и папки.

Это необходимо организовать в первую очередь. Нужно всегда начинать с ServerRoot директории настроенной в Apache или каком-нибудь другом HTTP сервере, все описанные далее папки идут относительно нее.

. /css(опционально ссылка)

. /ext (ссылка)

. /img (ссылка)

. /js

index.html

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

* css будет содержать все ваши таблицы стилей. Если у вас есть глобальные таблицы стилей с фирменными цветами и шрифтами можно создать в CSS каталоге ссылку.

* ext ссылки на дерево ExtJS библиотек разных версий.

* img ссылки на изображения. Он может содержать также подкаталоги.

* js будет содержать все скрипты вашего приложения.

* index.html файл HTML, который является отправной точкой вашего приложения. Вы можете назвать его как хотите, и вам может понадобиться еще несколько файлов, например, для авторизации.

* По желанию, вы можете создать директорию или ссылку на ваши серверные скрипты (у меня есть. / classes).

(Прим.Переводчика: ссылки для Linux).

index.html

Примерное минимальное содержимое файла index.html выглядит следующим образом:


<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

<link rel="stylesheet" type="text/css" href="./ext/resources/css/ext-all.css">

<link rel="stylesheet" type="text/css" href="./css/application.css">

<script type="text/javascript" src="./ext/adapter/ext/ext-base.js"></script>

<script type="text/javascript" src="./ext/ext-all-debug.js"></script>

<script type="text/javascript" src="./application.js"></script>

<title>A Big Application</title>

</head>

<body></body>

</html>

application.js

Нам нужен файл в котором будет размещена функция onReady, давайте назовем его application.js. Минимальное содержание выглядит так:


/**

* An Application

*

* @author    Ing. Jozef Sakáloš

* @copyright (c) 2008, by Ing. Jozef Sakáloš

* @date      2. April 2008

* @version   $Id$

*

* @license application.js is licensed under the terms of the Open Source

* LGPL 3.0 license. Commercial use is permitted to the extent that the

* code/component(s) do NOT become part of another Open Source or Commercially

* licensed development library or toolkit without explicit permission.

*

* License details: http://www.gnu.org/licenses/lgpl.html

*/

/*global Ext, Application */

Ext.BLANK_IMAGE_URL = './ext/resources/images/default/s.gif';

Ext.ns('Application');

// основная точка входа нашего приложения

Ext.onReady(function() {

Ext.QuickTips.init();

Здесь будет код вызова основного класса приложения

});

// eof

Ваш header и footer может быть различным, но уверен, вы должны установить параметр Ext.BLANK_IMAGE_URL, чтобы он указывал на картинку на локальном сервере. Это путь к 1 × 1px прозрачной картинке, которая используется Ext для пустых областей, если параметр указывает на неправильное место, у вас могут возникнуть различные проблемы — такие, как отсутствие изображения-переключателя у Combobox, либо отсутствие иконок.

Вам также может понадобиться создать новую глобальную переменную-объект для приложения (в данном случае это Application).

Вы должны быть уверены, что Ext.onReady, это начало вашего приложения — место, где вы пишете его инициализацию.

css/application.css

Вы будете хранить ваши css стили в этом файле. Если вам нужно всего лишь несколько правил, то может показаться, что нет необходимости создавать отдельный файл для них, и что это хорошая идея положить их в тег <style> в заголовке.

Это не так, помните, что вы пишете большое приложение, так что все должно быть на своем месте. Если вы поместите стили в header, страницы рано или поздно, у вас появится проблемы с ними. И вы не будете знать где они находятся.

Как делать Неправильно!

Что мы обычно делаем когда узнали основы, правильно, начинаем писать код:

var vp = new Ext.Viewport({
layout:'border'
,items:[
new Ext.grid.GridPanel({
store:new Ext.data.Store({
proxy:new Ext.data.HttpProxy({ ...

Подождите минутку. Так мы очень скоро получим более 10000 строк в нашем файле application.js, а это то, что мы хотим в самую последнюю очередь. Очевидно мы что-то пропустили, если мы создаем такой большой файл, почему бы нам вообще не написать все в index.html.

Правильное решение — разделить все!

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

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

Предварительно настроенные классы.

Итак, сейчас, когда вы определились со структурой вашего приложения, вы начнете писать первый из компонентов. Но каким образом ? Лучше решение — это расширить классы компонентов ExtJS, добавить в них конфигурационные параметры. Я называю такие объекты пред настроенными компонентами, они редко добавляют какой-то функционал в стандартный класс ExtJS, но главная цель этого — пред настройка. Например чтобы иметь преднастроенный grid, с собственномы ColumnModel, store, sorting option, editor и т.д.  делаем следующее:

Application.PersonnelGrid = Ext.extend(Ext.grid.GridPanel, {
border:false
,initComponent:function() {
var config = {
store:new Ext.data.Store({...})
,columns:[{...}, {...}]
,plugins:[...]
,viewConfig:{forceFit:true}
,tbar:[...]
,bbar:[...]
}; // eo config object

// Применяем config
Ext.apply(this, Ext.apply(this.initialConfig, config));

Application.PersonnelGrid.superclass.initComponent.apply(this, arguments);
} // eo function initComponent

,onRender:function() {
this.store.load();

Application.PersonnelGrid.superclass.onRender.apply(this, arguments);
} // eo function onRender
});

Ext.reg('personnelgrid', Application.PersonnelGrid);

После создания преднастроенного класса мы можем его использовать следующим образом:

var win = new Ext.Window({
title:'Personnel'
,widht:600
,height:400
,items:{xtype:'personnelgrid'}
});
win.show();

Что мы сделали ? Мы расширили класс Ext.grid.GridPanel создав новый класс Application.PersonnelGrid и мы зарегистрировали его как xtype с именем personnelgrid.

Мы настраиваем класс GridPanel всеми необходимыми функциями, которые нужны, чтобы этот класс стал объектом PersonnelGrid. С этого момента у нас появился новый компонент, строительный блок нашего приложения, который мы можем использовать в любом месте ( в окне, в таблице, самостоятельно — отдельно от всего остального). Мы можем создать его двумя способами:

//Напрямую через объект
var pg = new Application.PersonnelGrid();

// или используя его xtype имя
var win = new Ext.Window({
items:{xtype:'personnelgrid'}
,....

});

Организация пред настроенных классов.

Приведенный выше код не нужно помещать в функцию OnReady, поскольку он не имеет ничего общего со структурой DOM, а лишь создает новый объект JavaScript. Поэтому он может и должен быть записан в отдельный файл (js/Application.PersonnelGrid.js) и должен быть включен в заголовок index.html следующем образом:

<script type="text/javascript" src="./js/Application.PersonnelGrid"><script>

Пока все хорошо, у нас практически все на своем месте, и почти все что нам необходимо в дальнейшем это писать вот такие пред настроенные классы, помещать их в каталог ./js, добавлять в index.html, и собирать приложения из этих компонентов, как мозайку из составных частей.

Выглядит неплохо, правда ?

Хотя есть еще кое что, что необходимо знать.

Коммуникация между компонентами.

Представьте себе, что нам нужно разместить в одном месте справа TabPanel (панель с вкладками), а слева список ссылок. Нажимая на ссылку мы будем создавать новую владку на панели справа. Куда мы должны поместить обработчик нажатия на кнопку слева или справа ? В TabPanel или в списке ссылок ?

Не в одном из них. Почему ? Если у нас есть предварительно настроенный класс, который создает список ссылок и поместим наш обработчик после этого кода, то он не будет знать ничего о TabPanel. В тоже время он должен использовать TabPanel.

Если мы поместим обработчик в TabPanel, то будет тоже самое, он не будет знать на какую именно ссылку мы нажали.

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

Итак, что мы должны делать ? Наш главный контейнер должен слушать событие от списка ссылок и должен в ответ на это событие создавать кладки в TabPanel. Компонент который описан в этом примере можно увидеть здесь Saki’s Ext Examples.

Production системы.

Когда мы пишем таким образом большое приложение у нас в скором времени в index.html образуется множества .js вложений (у меня в одном приложении около 80, и продолжает с каждым днем расти). Это может снизить быстродействие системы.

Лучший способ решить эту проблему, объединить все файлы в один при публикации вашего приложения. Это лучше всего сделать с помощью программы для уменьшения и склеивания .js файлов (Прим.переводчика: я использую YUI Compressor в Eclipse).  Кроме того на сервере вам не нужна debug версия ExtJS, которую вы используете при разработке. В конечном итоге на сервере у вас должно получится следующее:

* ext-all.js
* app-all.js and
* application.js

Заключение.

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

Удачного программирования!

Источник: http://blog.extjs.eu/know-how/writing-a-big-application-in-ext/

Часть 2 и Часть 3.

4 thoughts on “Написание больших приложений на ExtJS (Часть1)

  1. Большое спасибо за статью! Давно искал информацию именно про организацию структуры ExtJS приложения. Во всех статьях/примерах, и даже официальной документации, даются отрывки кода как вы написали в абзаце «Как делать Неправильно!». А когда берешься за реальный проект, который к тому же не маленький, обязательно сталкиваешься с проблемой организации ExtJS кода.

    Вообщем материал очень нужный и полезный. Ещё хотелось бы не больших комментариев прямо в статье по функциям Ext.apply, Ext.extend итд.., ну чтобы читалось проще тем, кто не очень знаком с ExtJS. Ну и разумеется, интересно что изменилось в плане организации структуры кода для новой ветки ExtJS’a 3.X.X.

  2. Рад что статья была вам полезна. В плане организации кода, в новой версии ничего не изменилось.

  3. Воооот! Вот такой статьи мне очень не хватает вожусь с фреймворком уже неделю, а код уже превратился в большую портянку(((

    а для ветки 4.x подойдут ваши советы ?

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

Comments are closed.