ExtJS Classic Создание классических приложений Краснов Александр

advertisement
Краснов Александр
ExtJS Classic
Создание классических приложений
Вспомнить все
• ExtJS - библиотека JavaScript для разработки веб-приложений и
пользовательских интерфейсов
• Classic – классические приложения (desktop)
• Modern – планшеты, телефоны
• Sencha CMD – приложение для создания и последующей работой
с проектом
• app build – построение проекта
Создание первого приложения
«Галопом по Европе»
• Загружаем GPL файлы
• Генерация проекта с помощью Sencha CMD
• Знакомство с MVVM
• Создание собственного раздела
• Посторонние проекта
• Публикация проекта
Поехали!
• Скачиваем GPL лицензию https://www.sencha.com/legal/GPL/
• Устанавливаем Sencha CMD
https://www.sencha.com/products/extjs/cmd-download/
• Выполняем команду
sencha -sdk "D:\ext-6.0.0-gpl\" generate app MyApp classic
“D:\MyApp“
В каталоге с приложением выполняем: app build
Мой проект
• Открываем проект в Visual Studio как Web Site
• Добавляем файл web.config и дописываем следующий код
<system.webServer>
<staticContent>
<remove fileExtension=".json"/>
<mimeMap fileExtension=".json" mimeType="application/json"/>
<remove fileExtension=".appcache"/>
<mimeMap fileExtension=".appcache" mimeType="xml/text" />
<remove fileExtension=".woff"/>
<mimeMap fileExtension=".woff" mimeType="font/x-woff" />
<remove fileExtension=".woff2"/>
<mimeMap fileExtension=".woff2" mimeType="application/font-woff2"/>
</staticContent>
</system.webServer>
• Запускаем приложение F5(CTRL+F5)
Внимание, бывают «обломы»
Даже разработчики sencha ошибаются
Иногда после выполнения команды app build выходит ошибка
Sencha CMD не смогла сгенерировать css стили. Что делать?
• удалить данные из папки build
• изменить тему в файле app.json
Знакомство
«Тернистый путь к знаниям»
• app – папка файлами приложения
• model – модели
• store – хранилища
• view - представления
• build - папка с построенным приложением для публикации
• ext – папка с файлами extjs’a
• resources – хранение статичных файлов (jpg, json, xml и т.д.)
• sass - стили
• app.json – настройка приложения
Далее подробно
Все создаваемые(используемые) объект в приложении требуется
хранить в папке app.
И дополнительно прописать их в файле app.json
Данное действие позволит приложению sencha cmd
скомпилировать все js – файлы в один
Модели
Ext.define('MyApp.model.User', {
extend: 'Ext.data.Model', // наследование
fields: [
{name: 'name', type: 'string'},
{name: 'age', type: 'int'}
]
});
На уровень модели можно накладывать
валидацию
validators: {
age: 'presence',
name: { type: 'length', min: 2 },
gender: { type: 'inclusion', list: ['Male', 'Female'] },
username: [
{ type: 'exclusion', list: ['Admin', 'Operator'] },
{ type: 'format', matcher: /([a-z]+)[0-9]{2,3}/i }
]
}
Представление
Ext.define('MyApp.view.main.List', { // соответствует расположению в папке
extend: 'Ext.grid.Panel',
xtype: 'mainlist',
requires: [
'MyApp.store.Personnel' ], // обязательные элементы
controller: 'main', // ссылка на контроллер
viewModel: 'main', // ссылка на view model
title: 'Personnel',
store: {
type: 'personnel' }, // ссылка на хранилище
columns: [
{ text: 'Name', dataIndex: 'name' },
{ text: 'Email', dataIndex: 'email', flex: 1 },
{ text: 'Phone', dataIndex: 'phone', flex: 1 } ],
listeners: { // события
select: 'onItemSelected'
}
});
MyApp.view.main.List
Контроллер
Ext.define('MyApp.view.main.MainController', {
extend: 'Ext.app.ViewController', // базовый класс
alias: 'controller.main', // псевдоним для дальнейшего использования
onItemSelected: function (sender, record) { // метод определенный во view
Ext.Msg.confirm('Confirm', 'Are you sure?', 'onConfirm', this);
},
onConfirm: function (choice) {
if (choice === 'yes') {
//
}
}
});
Примечание: Один контроллер может быть привязан к нескольким представлениям
ViewModel
Ext.define('MyApp.view.main.MainModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.main', // псевдоним
data: { // данные для привязки
name: 'MyApp',
loremIpsum: 'Lorem ipsum dolor sit amet'
}
//TODO - add data, formulas and/or methods to support your view
});
Есть возможность использовать «формулы»
formulas: {
name: {
get: function (get) {
var fn = get('firstName'), ln = get('lastName');
return (fn && ln) ? (fn + ' ' + ln) : (fn || ln || '');
},
set: function (value) {
var space = value.indexOf(' '),
split = (space < 0) ? value.length : space;
this.set({
firstName: value.substring(0, split),
lastName: value.substring(split + 1)
});
}
}
}
Примечание: В наших проектах мы используем ViewModel для хранения бизнес-логики
Хранилище (Store)
Ext.define('MyApp.store.Users', {
extend: 'Ext.data.Store',
alias: 'store.users',
model: 'MyApp.model.User', // модель
data : [
{firstName: 'Seth', age: '34'},
{firstName: 'Scott', age: '72'},
{firstName: 'Gary', age: '19'},
{firstName: 'Capybara', age: '208'}
]
});
Совместно с моделью
Ext.define('MyApp.store.Users', {
extend: 'Ext.data.Store',
alias: 'store.users',
fields:[‘firstName’, ‘age’]
data : [
{firstName: 'Seth', age: '34'},
{firstName: 'Scott', age: '72'},
{firstName: 'Gary', age: '19'},
{firstName: 'Capybara', age: '208'}
]
});
Без модели
Взаимодействие с сервером
AJAX
(proxy)
или
Store
REST
(proxy)
или
DIRECT
(proxy)
Server
Наш метод
Расслабляемся и получаем удовольствие
censored
• Поднимаем Direct Ext.Direct.addProvider(myProvider)
• Указываем в хранилище что используем proxy: direct
Ext.define('ImportSubstitution.store.NavigationMenu', {
extend: 'Ext.data.TreeStore',
alias: 'store.navigationMenu',
proxy: {
type: 'direct', // указываем Direct
directFn: 'PN.Util.It.Module.Extjs.ExtjsDirectRpc.GetNavigation‘ // имя функции на сервере
}
});
censored
Вкусности
• Роутинг
• Плагин
• Миксин (mixin)
• Наследование (expand)
• Bind’инг (связано с viewmodel)
Роутинг
Ext.define('MyApp.view.main.MainController', {
extend : 'Ext.app.ViewController',
routes : {
'users' : 'onUsers‘,
‘user/:id’: ‘onUser’
},
onUsers : function() {
//...
},
onUser: function(id){
//...
}
});
Ext.define('MyApp.Application', {
extend : 'Ext.app.Application',
//...
Инициализация перехода на другую «страницу»
this.redirectTo('user/1234');
defaultToken : 'home'
});
Настройка «страницы» по умолчанию
Плагины
Можно «встроить» дополнительный функционал
Ext.define('It.prototype.plugin.OpenForm', {
extend: 'Ext.AbstractPlugin',
alias: 'plugin.proto-openform',
init: function (component) {
var me = this;
var results = component.getDockedItems().filter(function (dock) {
return dock.dock == 'top' && dock.xtype == 'toolbar'
});
var toolbar;
if (results.length == 0) { // строим toolbar
toolbar = component.addDocked({
xtype: 'toolbar',
dock: 'top'
})[0];
} else { // выбираем найденный
toolbar = results[0];
}
toolbar.insert(0, { // добавляем кнопку на форму
xtype: 'button',
text: 'Открыть форму',
handler: function (btn) {
me.onClick();
}
});
...
}
if (results.length != 0)
toolbar.insert(1, '|');
применение
Ext.define('It.grid.Panel', {
extend: 'Ext.grid.Panel',
alias: ['widget.itgridpanel', 'widget.itgrid'],
….
initComponent: function () {
var me = this;
…
me.plugins.push({
ptype: 'proto-openform',
parentContainerByListView: 'tabpanel'
});
…
this.callParent(arguments);
},
…
MIXIN
Наделение дополнительными функциями
Ext.define('It.data.queryable.GridQueryable', { // обычный класс ExtJS
extend: 'It.data.queryable.BaseQueryable',
writeSelectQuery: function () { // этот метод вызывается в базовом классе
var me = this;
Ext.each(me.columns, function (column) {
me.pushColumn(column);
});
},
});
pushColumn: function (column) {
var me = this;
var items = this.getSelectQueryables();
if (column.hidden !== true) {
if (column.columns) {
Ext.each(column.columns, function (item) {
me.pushColumn(item);
});
} else {
items.push({
dataIndex: column.dataIndex,
alias: column.columnAlias
});
Применение
}
}
}
Ext.define('It.grid.Panel', {
extend: 'Ext.grid.Panel',
alias: ['widget.itgridpanel', 'widget.itgrid'],
mixins: ['It.data.queryable.GridQueryable', 'It.data.IncludeToRPC'],
…
changeProxy: function () {
if (this.updateSelectParams
&& this.store.getProxy().type != 'memory') {
this.updateSelectParams();
this.store.load();
}
},
…
Наследование
Все как у всех
Ext.define('It.data.queryable.BaseQueryable', {
selectQueryables: null,
getSelectQueryables: function () {
return this.selectQueryables;
},
selectQueryableToString: function () {
var me = this;
var result = '';
….
return result.substr(0, result.length - 1);
},
updateSelectParams: function () {
var me = this;
me.writeSelectQuery(); // вызов дочерней функции
me.store.proxy.extraParams['select']
= me.selectQueryableToString();
}
});
Ext.define('It.data.queryable.GridQueryable', {
extend: 'It.data.queryable.BaseQueryable', // наследование
writeSelectQuery: function () { // переопределенная функция
var me = this;
Ext.each(me.columns, function (column) {
me.pushColumn(column);
});
},
pushColumn: function (column) {
…
}
});
Bind’инг
Простой пример
Ext.define('MyApp.view.home.HomeModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.home',
data: {
firstName: 'Александр',
lastName: 'Краснов'
},
formulas: {
name: function (get) {
return get('firstName') + ' ' + get('lastName');
},
}
});
Ext.define('MyApp.view.home.Home', {
extend: 'Ext.Container',
viewModel: 'home',
items: [
{
bind:{
html: 'Hello {name}'
}
}
]
});
Пример
• Создание приложение
• Настройка роутинга
• Простейшая форма
• ViewModel (Bind’инг)
• Публикация
Всем спасибо!
Доклад окончен
Полезные ссылки
• http://it.chuvashia.com
• http://docs.sencha.com
• http://www.google.ru 
2015 © Краснов Александр
Download