вторник, 5 октября 2010 г.

Ext JS больше нет! Начинаем работу с Ext JS

[статья в работе]
JQuery, Prototype, Mototools … Эти javaScript библиотеки серьёзно облегчают жизнь веб – разработчику. Ту же миссию призвана осуществить библиотека Ext JS, но «это нечто совсем другуе”. И тут всё гораздо серьёзней. Впрочем, давайте посмотрим что собой представляет этот инструмент.

В середине июня этого года, разработчики популярного JavaScript- фреймворка Ext  JS решили завершить жизненный цикл своего проекта. Впрочем событие, которое по всей видимости будет иметь довольно большие последствия для веб-разработчиков, состоит в том, что  авторы библиотеки теперь будут выпускать новый продукт, вернее несколько продуктов, объединенных под новым названием – Sencha (кажется, чай такой есть).  В их основе всё та же Ext  JS, объединенная с проектами jQTouch и Raphaël. Что из этого выйдет пока не  ясно, но определённо, для разработчика не знакомого с библиотекой, стоит обратить на неё внимание. Чем мы сегодня и займёмся.
Ext JS изначально появилась как расширение Yahoo! UI Library (YUL), но дальнейшем развилась в самостоятельный проект. От своей прародительницы фрэймворк унаследовал некоторое количество лицензионных проблем, которых в этой статье касаться не будем.
Чем Ext JS отличается от других популярных JavaScript фрэймворков (Prototype, jQuery,Dojo и т д)? Прежде всего это библиотека готовых форм, виджетов, визуальных компонентов. В её базовых классах их уже столько, что, на первый взгляд  они перекрываю все мыслимые потребности веб разработчика, а ведь есть ещё более сотни пользовательских расширений.
В Ext JS присутствуют инструменты для низкоуровневой работы с DOM элементами и стилями, но библиотека рассчитана на более высокоуровневую разработку.

Начинаем
Сначала забираем последнею версию , всё таки пока просто Ext JS, с сайта библиотеки (http://extjs.com/products/extjs/download.php). Распаковываем её на территорию, доступную вашему веб-серверу. Что бы вы не использовали, в качестве такового, будем считать, что на этом установка закончена. Сегодня мы занимаемся клиентской стороной,
Библиотека поставляется с довольно подробно, хоть и немного своеобразно, документированным API, но создатели рекомендуют изучать её запуская примеры, которые поставляются с дистрибутивом и ковыряя их код. Но мы попытаемся с ходу создать что-нибудь интересное сами.

Вот такой вот Hello Word
Создадим в корне нашего сервера папку extpjs. В ней файл index.html, со следующим содержанием:

<html>
<head>
<meta > http-equiv="Content-Type" content=text/html; charset=utf-8"/>
<title id='title'>Ext JS!<title>
<link rel="stylesheet" type="text/css" href="../ext-3.2.1/resources/css/ext-all.css"/>
<script type="text/javascript" src="../ext-3.2.1/adapter/ext/ext-base.js" >
</script>
<script type = "text/javascript" src = "../ext-3.2.1/ext-all-debug.js" >
</script>
<script type = "text/javascript" >
Ext.BLANK_IMAGE_URL ='../ext-3.2.1/resources/images/default/s.gif';  Ext.onReady(function({
alert('Hello Ext JS!');
});
</script>
</head>
<body>
</body>
</html>

Предполагается, что библиотека находиться в папке ext-3.2.1, расположенной так-же в корне веб сервера. Понятно, что вам нужно изменить пути на свои, да и версия может быть другой.
Тут всё совсем просто – мы подключаем базовые стили и библиотеки, базовый адаптер (об архитектуре чуть позже). Затем ext-all-debug.js подключаем все базовые виджеты (в реальном приложении так делать не нао). Всё, библиотеку можно использовать.
 То что заключено в скобки поспле Ext.onReady выполниться после загрузки библиотеки, и сходные конструкции есть и у Prototipe и естесчтвенно у jQuery. После загрузки страницы, если всё сделано правильно появится обычное окно с сообщением.
Не очень впечатляет, правда? Мы это сейчас исправим.
 Немного переделаем код:
Ext.onReady(function(){   
         
      Ext.MessageBox.show({
                   title: 'Hello Ext JS',
                   msg: 'Hello!',
                   buttons: Ext.MessageBox.OK,
                   minWidth: 200,
                   icon: Ext.MessageBox.INFO
                })          
        });
 
Теперь смотрим результат (рис 1). Ничего особенного, но уже не так скучно.

 Рис. 1 Hello Word по ExtJS-ному

Что мы сделали? Использовали один из объектов библиотеки – MessageBox, вызвав его метод Show, и описав его пользуясь тем, что обычно называется термином «декларативный синтаксис». Это когда вместо честного воплощения алгоритмов, разработчик просто описывает свойства объекта, который хочет получить. Ext JS предоставляет нам такую возможность, и это здорово!
В этом состоит ключевая особенность библиотеки – она представляет собой набор веб-виджетов с вожможностью гибкого конфигурирования внешнего вида и заданием поведения, с помощью функций обратного вызова.кстати, последнее можно добавить и нашему хеллоуводу:
Ext.MessageBox.show({
                   title: 'Hello Ext JS',
                   msg: 'Hello!',
                   buttons: Ext.MessageBox.OK,
                  minWidth: 200,
                   icon: Ext.MessageBox.INFO,
                   fn: Result
                })
          
        });
        function  Result(){
            alert("callbackTest!");
            }
Теперь при нажатии на кнопку «OK» будет выполнена функця Result(){, которой можно, разумеется, добавить и реалиизацию и более сложной бизнес-логтики.
В коллекцию виджетов библиотеки входят различные элементы управления, от кнопок и продемонстрированных месаджебоксов до сложных деревьев и окон. Естественно, особое внимание уделено компонентам HTML форм, каждый из которых реализован в библиотеке в расширенном виде, с дополнительными возможностями.
Каждый из реализованных компонентов может быть сконфигурирован, путём декларации и последующего изменения всех его параметров. Большинство из них генерируют события, как реакцию на изменения своего состояния. Внешний вид компонентов задается с помощью одной или нескольких таблиц стилей. Впрочем мы будем использовать дефолтную.
Попробуем сделать пкакую нибудь более сложную конструкцию. Пусть это будет панель с вкладками-табами. Простейший её вариант следующим образом:
            var tabs2 = new Ext.TabPanel({
            renderTo: Ext.getBody(),
             width:450,
                   height:450,
                  activeTab: 0,
                   frame:true,
              items: [{
                  title: 'Tab 1',
                        html: 'Простой Tab'
                  },{
                        title: 'Tab 2',
                        html: 'Ещё Tab'
                 }},{
                        title: 'Tab 3',
                        html: 'И ещё Tab'
                 }
}]
});
Результат на рис. 2
Впрочем панель с вкладками гораздо удобнее создавать на основе уже имеющихся DOM элементов.  Попробуем сделать что-нибудь что-нибудь более полезное.
Сначала  соорудим html конструкцию для будущей панели:

   
       
               In 1970, this British quintet released a couple of albums                    that made no bones about aping the approach of Fairport                     Convention (then at their peak). A mixture of traditional folk songs and originals, extended electric-guitar heavy                            arrangements, …
       
       
        
          
                
  • On the Shore 1970



























  •            
  • The Garden of Jane Delawney 1970



























  •            
  • Trees       2001



























  •            
  • Back to Roots



























  •              
  • Forrest Fires



























  •          
            
     
           
           
             
             
           
           
       

    Как видите, тут созданы три элемента DIV, внутри которых содержиться биография, дискография и фото некой рок – группы (в данном случае это замечательный британский состав Trees, но, к сожалению это к делу не относиться)
    Теперь пишем код, который расположит каждый DIV в своей вкладке:

    Тут мы создаём новый элемент класса TabPanel, привязываес его к идентификатору обрамляющего DIVа, задаём некоторые настройки и создаём три таба, так-же привязав их к уже свёрстанным DIVам.
    Всё! Вот так просто мы получили готовую панель с рабочими, переключаемыми вкладками (рис 3).
    Довольно полезным элементом является также окно (window), которое так-же может быть построено всего несколькими строчками кода. Мы, правда, сразу напишем их чуть больше, но дополнительные функции того стоят:
    var cont='';
    var w = new Ext.Window({
        title: 'Window',
        width: 560,
        autoHeight: true,
        items: {
            title: 'Collapse Me',
            height: 560,
            collapsible: true,
            border: false,
            html: '

    Trees

    ',
            padding: 40,
            listeners: {
                beforecollapse: function() {
                    w.el.shadow.hide();
                },
                beforeexpand: function() {
                    w.el.shadow.hide();
                },
                collapse: function() {
                    w.syncShadow();
                },
                expand: function() {
                    w.syncShadow();
                }
            }
        }
    }).show();

    Результат на рис. 4. На рисунке, конечно нельзя увидеть поведения окна, но по коду можно догадаться, что оно сворацивается/разворачиваетсчя при нажатии на стрелку, перемещается, при «захвате» мышкой за заголовок.
    А можем мы поместить в это окно панель из предъидущего примера? Да запросто! Чуть чуть изменим код:
            collapsible: true,
            border: false,
           // html: '

    Trees

    ',
            contentEl: 'tabs1',
            padding: 40,
            listeners: {
            ……………

    Результат можно видеть на рис. 5
    Безусловно, самым мощным, да и самым востребованным компонентом библиотеки является Grid – класс для работы с табличными данными. Сейчас попробуем реализовать простейшую таблицу. Сначала создадим модель данных:
    Ext.onReady(function(){
        var store = new Ext.data.ArrayStore({
            fields: [
                      {name: 'name'},
                      {name: 'price', type: 'float'},
                      {name: 'change', type: 'float'},
                      {name: 'pctChange', type: 'float'},
                      {name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
                            ]
                        });
    В данном случае поля таблицы (при необходимости с назначением типа и формата) описаны в массиве fields.
    Теперь создадим массив с данными:
          

    var myData = [
                  ['Samsung N127 (LA01RU)',346.67,0.02,0.03,'9/1 12:00am'],
                  ['Samsung N130 (KA03)',354.9,0.42,1.47,'9/1 12:00am'],
                  ['Samsung N150 (KA02)',358.33,0.28,0.34,'9/1 12:00am'],
                  ['Asus Eee PC 1001PX',370.279,0.01,0.02,'9/1 12:00am'],
                  ['Acer Aspire One (LU.SCM0D.001)',385.799,0.31,0.49,'9/1 12:00am'],
                  ['HP Compaq Mini(WR254EA)',386.73,-0.48,-1.54,'9/1 12:00am'],
                  ['Lenovo IdeaPad S10-3-2KB-B',401.62,0.53,0.71,'9/1 12:00am'],
                  ['Lenovo ThinkPad X100e (NTS4TRT)',442.50,0.92,1.39,'9/1 12:00am']
                        ];
    Тут, я думаю пояснений не требуется.
    Загрузим данные в модель:
    store.loadData(myData);
    Наконец создадим таблицу:
    var grid = new Ext.grid.GridPanel({
              store: store,
                     columns: [
                       {id:'name',header: 'Name', width: 240, sortable: true, dataIndex: 'name'},
                       {header: 'Price', width: 75, sortable: true, renderer: 'usMoney', dataIndex: 'price'},
                       {header: 'Change', width: 75, sortable: true,  dataIndex: 'change'},
                         {header: '% Change', width: 75, sortable: true,  dataIndex: 'pctChange'},
                         {header: 'Last Updated', width: 85, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
                            ],
                        stripeRows: true,
                        autoExpandColumn: 'name',
                        height: 200,
                        width: 480,
                        title: 'My Grid',
                        stateful: true,
                        stateId: 'grid'       
                        });
    grid.render('grid-example');
       });
    Создаём в теле страницы HTML – элемент-контейнер:
    <div style="margin:100px;" id="grid-example">div>
    И смотрим результат в браузере (рис 6).
    Как видите мы получили полноценную электронную таблицу, с возможностью сортировки по каждому столбцу, отображением отдельных столбцов и прочими обычными удобствами.
    Разберём немножко подробней создание таблицы. После указания источника данных  мы перечисляем поля таблицы, с точки зрения их отображения. Поле dataIndex при этом указывает на поле в созданном ранее источнике данных, а renderer отвечает за HTML отображение данных поля. В данном случае, оно используется для формирования полей Price (в доллдарах США, сравните начальные данные и отображаемые в таблице) и Last Updated (тут используется встроенная функция библиотеки). Впрочем, аргументом для renderer может быть и пользовательская функция. Немного изменим код:
    {header: 'Change', width: 75, sortable: true, renderer: change, dataIndex: 'change'},
    {header: '% Change', width: 75, sortable: true, renderer: pctChange, dataIndex: 'pctChange'},

    И добавим требуемые фукнкции:

    function change(val){
      if(val > 0){
       return '' + val + '';
      }else if(val < 0){
       return '' + val + '';
      }
       return val;
     }
                     
    function pctChange(val){
      if(val > 0){
        return '' + val + '%';
      }else if(val < 0){
        return '' + val + '%';
      }
        return val;
    }
     Теперь в таблице подсвечены отрицательные значения (рис. 7)
    В коллекции виджитов Ext JS есть ещё немало всего – реализолваны деревья, видеогалереи, таск-менеджер и даже, хм, WebDesktop (рис. 8). Как сделать такую красоту, вы можете самостоятельно узнать изучая код примеров, а сейчас предлагую загплянуть немного «под капот» библиотеки.
    Архитектура Ext JS
    В ядре (Core) фрэймворка сосредоточены базовые функции, необходимые для обеспеченя работы остальных компонентов. Оно разбито на несколько функциональных модулей, функции которых доступны внутри библиотеки.
    Один из них отвечает за отрисовку инициализацию визуальных компонентов, другой отвечает за Drag&Drop эффекты (ничего удивительного – ведь это по сути взаимодействие отдельных виджетов). Отдельный «ядерный» компонент - State Manager, отвечает за сохранения состояний компонентов, ещё один – UpdateManager, позволяет заново отрисовывать части страницы в соответствии с изменённым состоянием.
    В ядрое-же реализованы самые низкоуровневые опепрации – работа с простыми типами данных, с DOM морделью и подключаемыми адаптерами. Все эти функции также доступны и могут применяться при разработки простых приложений.
    Далее идут базовые функции работы посредством AJAX, базовые классы визуальных компонентов.
    Утилиты (util)отвечают за работу стилями, JSON, Куками, форматом данных и прочими «used» вещами.
    Как я упоминал, любые низкоуровневые функции можно вызывать непосредственно, но особенность. Архитектуры Ext JS является использование адаптеров (adapter)которые и предоставляют прозрачный интерфейс к всему функционалу. Именно их и используют находящиеся на вершине иерархии «продвинутые» классы виджеттов, такие, как menu, form или Layout (компоновщики). На том же уровне находятся и с средства работы с данными, но это отдельная тема, о которой можно поговорить в другой раз.
    Следует заметить, что кроме «родного» для Ext JS адаптера, используемого по умолчанию, существуют адаптеры к популярным JavaScript библиотекам – Prototype, JQuery и YUI, которые подключаются вместе с основной библиотекой, для возможности использования этих сред.
    Производительность
    После такого краткого экскурсы в возможности библиотеки, может встать вопрос: почему она таки не стала лидером среди JavaScript фрэймворков? Ответ очень прост. Как и её «бабушка» YUI,  ExtJS имеет доволдьно большой размер загружаемого файла ядра, что вроде бы указывает на место её применения – интранет, внутриофисные, корпоративные порталы.
    Впрочем, с тяжеловесностью ExtJS можно и нужно бороться (ведь и офисы сейчас бывают раскинуты по разным городам и даже странам). Просто (как уже говорилось в начале статьи) не стоит загружать все классы библиотеки. Она достаточно модульная и вполне возмождно загрузить только базовые модули и необходимые компоненты. В принципе это можно сделать в ручную (особенно при использовании и двух-трёх простых виджетов), но для штатного применения существует спрециальный билдер (http://www.sencha.com/products/js/build/, рис. 9) позволяющий сделать собственную сборку ExtJS, включающёю только необходимые компоненты.
    Руководство по ExtJS само является воплощением концепций фрэймворка,  оно сделано в виде веб-приложения, с активным использованием компонентов библиотеки (рис. 10).
    Заключение
    Что ещё можно добавить? Да очень многое. ExtJS полноценный открытый фреймворк, имеющий удобные и расширяемые механизмы интеграции с другими веб-технологиями (Google Gears, Adobe AIR), открытую архитектуру,  позволяющею дополнять библиотеку Компонентами сторонних разработчиков. Для ExtJS уже существуют полноценные средства разработки.
    Каюсь, упустил я очень многое, но я и не рассчитывал в небольшой статье раскрыть все особенности фрэймворка. Ext JS – это огромный интересный мир, со своими законами и философией, я надеюсь, что у меня получилось заинтересовать им читателя.

    Ссылки к статье:
    Сайт проекта Sencha:
    Пользовательские расширения для ExtJS (самые разнообразные):

    Подписи к рисункам:
    1.      Hello Word по ExtJS-ному
    2.      Простая панель вкладками
    3.      Почти веб приложение!
    4.      Рукотворное окошко
    5.      Композиция элементов
    6.      Ecxel взрогнул
    7.      «Умная» таблица
    8.      Рабочий стол в браузере
    9.      Собираем свой вариант библиотеки
    10.  Руководство пол Ext JS API

    Комментариев нет:

    Отправить комментарий