Создание сложных приложений в ExtJS
Раздел:
Programming /
Ajax
@
29.05.2008 |
Ключевые слова: extjs framework ajax
Источник: habrahabr
Предисловие
Я решил написать эту статью для тех пользователей Ext 2.x, которые уже переросли одну единственную HTML-страницу со встроенными скриптом, создающим простое окно или форму, для тех, которые уже решили, что Ext — это их путь и для тех, которые превозмогая трудности связанные с большими объемами кода, понимают, что нуждаются в его структурировании.
Сколько людей, столько и мнений. И поэтому способ, который я опишу ниже, не является одним единственным возможным. Также хотелось бы отметить, что не каждое приложение, написанное с применением этого подхода, является гарантированно хорошим. Ничего подобного.
Замечу, что описываемый подход является работоспособным, четко структурированным, без труда поддерживаемым и, одним словом: рабочим!
Что значит сложное приложение?
Когда вы оперируете объектом Viewport с BorderLayout, grid-таблицей и формой в одном файле, это, конечно же, не сложное приложение, правда? Если же у вас десятки окон, в каждом из которых grid-таблицы, формы или BorderLayout и все это добро раскидано по десяткам файлов, то это уже сложное и большое приложение, верно?
В немецком языке имеется одно милое словечко: Jein = Ja + Nein
Ответом на оба приведенных утверждения будет Jein. Вопрос заключается в следующем: когда приложение становится большим и сложным? Ответ прост: в тот самый момент как вы начинаете его таковым ощущать. Это момент когда становится сложно ориентироваться в большом количестве файлов или начинаются проблемы при поиске определенного места в случае попытки понять отношение компонентов, например, и так далее.
Можно с уверенностью говорить, что каждое приложение сложно столь же насколько простое достойно быть хорошо написанным и может стать по-настоящему большим, как только мы начнем добавлять новый функционал, наращивать объем кода, добавлять правила CSS и т.д. Лучшей и самой безопасной установкой при создании нового приложения является — «Я начинаю сложное приложение!»
Файлы и директории
То, что необходимо организовать в первую очередь. В нашем распоряжении всегда имеется каталог DocumentRoot так что все подкаталоги, затронутые ниже, будут приводиться относительно него.
Рекомендуемая структура каталогов:
- ./css (опциональная link)
- ./ext (ссылка)
- ./img (ссылка)
- ./js
- index.html
Слово «ссылка» означает, что каталог является мягкой ссылкой на реальный каталог, где лежат файлы. Преимущество этого приема в том, что, например, вы можете загрузить новую версию Ext в любой реальный каталог и заставить ссылку указывать на него, что избавит от редактирования путей в вашем коде. Можно проводить тестирование новой версии и если все в порядке, оставить ссылку указывать на новую версию, а если нет, то просто вернуть ее назад.
- css — хранилище всех ваших стилей. Если у вас имеются глобальные стили, вроде цветов компании или оформления шрифтов, то вы также можете создать этот каталог как ссылку;
- ext — ссылка на используемую вами версию Ext, как это было описано ранее;
- img — каталог с вашими изображениями. Также может содержать подкаталоги для иконок и т.п.;
- js — будет содержать все JavaScript файлы приложения, а также их скомпонованную версию;
- index.html — HTML-файл являющийся входной точкой вашего приложения. Вы можете назвать его как угодно, да и быть html-файлов может несколько, например, для операции аутентификации. Но в любом случае файл входной точки (с обработчиком onReady) должен быть один;
- дополнительно вы можете создать директорию или ссылку на серверную часть приложения (./classes в моем случае). Можно дать ей какое угодно имя, но следует выбрать согласующееся со всеми приложениями, которые вы разрабатываете (имена ./server, ./php будут неплохими вариантами).
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>
Хотя вы и можете работать с файлом подобным приведенному выше, я рекомендую добавлять заголовочную информацию как к этому типу файлов, так и ко всем иным. Маркер конца файла также имеет значение. См. примеры такого рода заголовков.
js/application.js
Нам понадобится файл, где мы сможем поместить onReady обработчик. Пусть его имя будет application.js. Минимальное содержимое такого файла приведено ниже:
// vim: sw=4:ts=4:nu:nospell:fdc=4
/**
* An Application
*
* @author Ing. Jozef Sakalos
* @copyright (c) 2008, by Ing. Jozef Sakalos
* @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`);
// application main entry point
Ext.onReady(function() {
Ext.QuickTips.init();
// code here
}); // eo function onReady
// eof
Ваши код может иным, но обязательным шагом будет установка Ext.BLANK_IMAGE_URL в значение, ссылающееся на ваш сервер. Это путь к прозрачному 1х1 изображению, которое используется Ext в качестве плэйсхолдера и если он ведет в пустоту, вы можете столкнуться с различными проблемами отрисовки такими как: отсутствие изображения стрелки в Ext.form.ComboBox, иконок и т.п. Возможно, что вам также понадобится создать глобальную переменную для вашего приложения (в данном случае это Application).
В чем вы должны быть уверенны, так это в том, что onReady обработчик наличествует у вас лишь однажды — в точке входа в приложение.
css/application.css
Поместите в этот файл все свои стили, если они у вас есть. В случае если вам необходимо лишь малое число таковых, то, возможно, не имеет смысла создавать для них отдельный файл. Можно записать их непосредственно в документ, используя <style>
.
Наоборот, помните, что вы создаете сложное приложение, стало быть, всему свое место. Если вы будете писать стили в заголовок документа, то вам рано или поздно придется решать проблемы с отрисовкой и вы не будете знать какие стили побудили их.
Как делать не надо
Что обычно следует за тем как был получен некий базис, такой, какой имеется у нас на данном этапе? Начинаем писать код. Итак, мы погрузились в кресло и начали творить:
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?
Правильный путь: разделяй и властвуй
Любое целое, вне зависимости от его размера, состоит из более малых систем, которые, в свою очередь, состоят из еще более малых частей, содержащих некоторые элементы. Ваше разрабатываемое сложное приложение не исключение. И вот сейчас как раз время чтобы определить для себя эти части, компоненты и связи между ними.
Итак, еще более удобно усядьтесь, хорошо подумайте, нарисуйте эскиз, составьте список, не принципиально, что вы будете именно делать, главное чтобы в результате у вас на руках был перечень компонент, из которых будет состоять ваше приложение. По крайней мере, главных из них.
Преднастроенные классы
Ну вот, как только вы покончили с анализом и определением составных частей своего приложения можно приступить к написанию одного из них. Как лучше всего это сделать? Наилучшим решением будет написание классов расширяющих стандартные компоненты Ext, ввиду того, что последние уже имеют все настройки, перезаписываемые переданными в их конструкторы значениями. Я называю такие расширения преднастроенными классами т.к. они редко вносят новый функционал и служат в основном для конфигурирования. Примером может служить grid-таблица «Персонал» со своею моделью колонок, хранилищем, настройками сортировки, редакторами и т.д.
В таком случае конфигурация нашего окна могла бы выглядеть следующим образом:
var win = new Ext.Window({
title:`Personnel`
,widht:600
,height:400
,items:{xtype:`personnelgrid`}
});
win.show();
Написание преднастроенного класса
Разберемся на примере:
Application.PersonnelGrid = Ext.extend(Ext.grid.GridPanel, {
border:false
,initComponent:function() {
Ext.apply(this, {
store:new Ext.data.Store({...})
,columns:[{...}, {...}]
,plugins:[...]
,viewConfig:{forceFit:true}
,tbar:[...]
,bbar:[...]
});
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);
Что у нас тут происходит? Мы расширяем Ext.grid.GridPanel, создавая новый класс-расширение Application.PersonnelGrid и регистрируем для него новый xtype с именем personnelgrid.
По сути, мы передаем обычной grid-таблице все настройки достаточные для превращения ее в специализированную grid-таблицу «Персонала». Начиная с этого момента, у нас имеется новый компонент, строительный блок нашего приложения, который мы можем использовать где угодно (в окне, на панели, самостоятельно) для отображения списка сотрудников. Создать его можно следующим образом:
var pg = new Application.PersonnelGrid();
или используя xtype (т.н. ленивое создание):
var win = new Ext.Window({
items:{xtype:`personnelgrid`}
,....
});
Организация и хранение преднастроенных классов
Код приведенный выше не нуждается, да и не будет запускаться в обработчике onReady — он не оперирует DOM, а просто создает JavaScript объект. Следовательно, он может и должен быть помещен в отдельный файл (js/Application.PersonnelGrid.js) и будет включаться в хедер index.html.
Что ж, пока все идет хорошо — у нас почти все готово и все (почти), что нам нужно так это продолжать описывать преднастроенный классы, класть их в ./js, включать в index.html и собирать наше приложение из их экземпляров как кусочки головоломки.
Выглядит неплохо, а?
Межкомпонентное сообщение
Представьте себе, что вам необходимо рамочный макет (border layout) со списком ссылок слева (west region) и панелью закладок посередине (center region). Щелчок по ссылке должен создавать новую закладку в центре. Где вы поместите логику всего происходящего, обработчик события и код создания? Слева или в центре?
Нигде. Почему? Если у нас есть преднастроенный класс, который создает и отображает список слева, а мы помещаем логику туда, то его существование теряет смысл без центрального региона. Мы просто не сможем использовать список без панели закладок.
Если же мы поместим логику в центральную область, итог будет схожим: панель закладок не может существовать без списка ссылок.
Есть только один компонент осознающий существование левой и центральной панелей — это их контейнер с рамочным макетированием, единственное правильное место для размещения логики межкомпонентного сообщения.
Производственная система
Ввиду соглашения об организации нашего приложения очень рано мы столкнемся с большим числом JavaScript файлов (в моем случае порядка 80 и их число растет с каждым днем), что может негативно сказаться на производительности реально работающей, не тестовой, системы.
Наилучшим решением является слияние (конкатенация) всех JavaScript файлов в нужном порядке следования итогом чего станет один большой файл, который затем необходимо сжать одним из инструментов минификации или сжатия.
Производственная система будет подключать:
- ext-all.js
- app-all.js
- application.js
Дополнительная информация по сжатию вашего кода, а также созданию файлов билдов может быть найдена в другом руководстве.
Заключение
В общем-то это все… Существуют специализированные техники для некоторых классов Ext, много иных серверных и клиентских фишек, но то, что было изложено выше — общая концепция.
Счастливого кодинга!
На правах переводчика:
- Статья зацепила меня тем, что описывает общую концепцию работы со сложным приложением в конкретном случае разработки в ExtJS;
- далее перевод планируется поместить в официальный мануал проекта рядом с оригиналом, поэтому просьба реагировать не только плюсами и минусами, но и в текстовом виде, пожалуйста;
- кажушийся странным танец вокруг ссылок при описании файловой организации обусловлен тем, что сами разработчики ExtJS интенсивно используют построение собранных из множества файлов билдов. В таком случае новая версия того же ExtJS это как все исходное дерево, так и билд фреймворка. Гораздо удобнее, конечно, изменить ссылку, чем копировать туда-сюда много файлов.
Это интересно:
Распечатать статью
Вернуться в раздел:
Programming /
Ajax
Реклама: