По неясным причинам запись исчезла из официального блога через несколько часов после публикации, а так же убран контент с демо сайта. Позже запись в блоге появилась вновь, но с сообщением о том что приложение будет доступно в ближайшее время
Сегодня команда разработчиков Sencha объявляет о выходе нового демонстрационного приложения основанного на их библиотеке: ShopStyle. ShopStyle это классическое приложения для iPhone и iPad которое является частью портала PopSugar. Представленное приложение было разработано на библиотеке Sencha Touch и использует одно из нововведений: Touch Carousel. В частности представлена “бесконечная карусель”, одна из новых возможностей которая является частью Sencha Touch. важнейшая особенность этого компонента — активное управление DOM которое позволяет приложению вписываться в ограничения по памяти существующие на iPad.
Разумеется вы можете изучить исходники на сайте, а в этой статье будут рассмотрены самые любопытные технические моменты в создании данного приложения. Основная проблема заключается в том что в одной категории могут находится тысячи товаров. Загрузка всех этих данных в память браузера разом — гарантированный фейл.
Карусель может обрабатывать тысячи элементов с помощью скользящей области просмотра которая отображает данные. Для текущей страницы создаются три области с контентом: текущая, предыдущая и последующая. В то время пока пользователь листает соответствующие области создаются и уничтожаются что обеспечивает соответствие контента текущему состоянию. Благодаря этому можно гарантировать что любой момент времени в карусели находится достаточно небольшое фиксированное количество элементов, несмотря на то что их реальное число может быть огромным. На схеме ниже скользящая область состоит из трех страниц. Первоначально сфокусирована третья страница и инициализированы страницы со второй по четвертую. Когда пользователь переходит к четвертой странице активная область смещается вправо, а так же удаляется вторая страница и создается пятая.
Инициализация карусели элементарна. Вместо непосредственного использования параметра items, определяется createItem который принимает функцию. когда будет необходимо инициализировать элемент будет вызвана функция с индексом элемента. Функция создает и возвращает элемент. Для демонсрации этого приведен небольшой кусок кода с обычной и бес конечной каруселью.
В принципе скользящая область достаточно проста. При инициализации и каждый раз при изменении области видимости обновляем скользящую область.
ShopStyle предоставляет API которое позволяет получать и фильтровать товары из категории. Так же есть возможность получения частей данных что необходимо для реализации постраничного отображения. Разработчикам хотелось иметь непосредственный доступ к данным, а так же избежать проблем вызванных получением данных из сети, а это означало кэшерование изображений.
Для этих целей был создан класс DataCache для упрощения получения данных и кеширования данных о товарах. в своей основе DataCache содержит простую функцию “getItems” которая принимает диапазон товаров а так же функцию для обратного вызова для обработки данных о товарах после их получения, так же она имеет некоторую простую обработку для избежания идентичных запросов и непосредственно возвращает данные которые уже были получены. В результате кеширование становится элементарным — все что необходимо так это вызвать getItems с диапазоном товаров. Этот процесс изображен на диаграмме:
Когда getItems вызывается для первых 100 элементов — отправляется запрос в ShopStyle. При последующих запросах getItems для элементов 1-10 и 11-20 приложение определяет что эти данные уже запрашиваются и не посылает дополнительные запросы в API. Когда приходит ответ вызываются соответствующий функции обратного вызова. При последующем обращении к getItems для элементов 21-30, сразу же идет вызов обратной функции так как данные уже были получены.
При отображении товаров каждая страница отображает 8 или 9 (в зависимости от ориентации) элементов в grid layout. В большинстве случаев используются плавающие элементы но разработчики захотели пойти несколько другим путем и использовать возможности CSS3:
Touch версия приложения не является полной копией оригинального приложения — например была реализована возможность поиска в то время как оригинальное приложение использует механизм фильтров. Все это демонстрирует преимущества Sencha Touch при создании аналогов приложений доступных на мобильных платформах, а так как это все таки интернет приложение то оно будет работать и на WebOS и на Android (сразу после того как разработчики допилят соответствующую поддержку в библиотеке) из коробки.
Ну и в заключении автор оригинальной статьи благодарит Brian Sugar и Trey Matteson из Sugar за предоставление доступа к API, а так же в консультировании по профильным вопросам и желает им всего.
Сегодня команда разработчиков Sencha объявляет о выходе нового демонстрационного приложения основанного на их библиотеке: ShopStyle. ShopStyle это классическое приложения для iPhone и iPad которое является частью портала PopSugar. Представленное приложение было разработано на библиотеке Sencha Touch и использует одно из нововведений: Touch Carousel. В частности представлена “бесконечная карусель”, одна из новых возможностей которая является частью Sencha Touch. важнейшая особенность этого компонента — активное управление DOM которое позволяет приложению вписываться в ограничения по памяти существующие на iPad.
Разумеется вы можете изучить исходники на сайте, а в этой статье будут рассмотрены самые любопытные технические моменты в создании данного приложения. Основная проблема заключается в том что в одной категории могут находится тысячи товаров. Загрузка всех этих данных в память браузера разом — гарантированный фейл.
Создание Карусели
Карусель может обрабатывать тысячи элементов с помощью скользящей области просмотра которая отображает данные. Для текущей страницы создаются три области с контентом: текущая, предыдущая и последующая. В то время пока пользователь листает соответствующие области создаются и уничтожаются что обеспечивает соответствие контента текущему состоянию. Благодаря этому можно гарантировать что любой момент времени в карусели находится достаточно небольшое фиксированное количество элементов, несмотря на то что их реальное число может быть огромным. На схеме ниже скользящая область состоит из трех страниц. Первоначально сфокусирована третья страница и инициализированы страницы со второй по четвертую. Когда пользователь переходит к четвертой странице активная область смещается вправо, а так же удаляется вторая страница и создается пятая.
Инициализация карусели элементарна. Вместо непосредственного использования параметра items, определяется createItem который принимает функцию. когда будет необходимо инициализировать элемент будет вызвана функция с индексом элемента. Функция создает и возвращает элемент. Для демонсрации этого приведен небольшой кусок кода с обычной и бес конечной каруселью.
// Normal carousel
var carousel = new Ext.Carousel({
items: [{
html: '1'
},{
html: '2'
}, {
html: '3'
}]
});
// Infinite carousel
var carousel = new SS.BufferedCarousel({
itemCount: 3,
createItem: function(index) {
return {html: (i+1)+''};
}
});
В принципе скользящая область достаточно проста. При инициализации и каждый раз при изменении области видимости обновляем скользящую область.
bufferCards: function(index) {
// Quick return if there is nothing to do
if (this.lastBufferedIndex == index) { return; }
this.lastBufferedIndex = index;
// Initialize variables
var
// size of the window
bufferSize = this.bufferSize,
// constrained start index of the window
start = (index-bufferSize).constrain(0, this.itemCount-1),
// constrained end index of the window
end = (index+bufferSize).constrain(0, this.itemCount-1),
items = this.items,
// flag to determine if any items were added/removed
changed = false,
// will be set to the item where its position == index
activeCard;
// make sure the index is within bounds
index = index.constrain(0, this.itemCount-1);
// cull existing items
var i = 0;
while (i < items.length) {
var item = items.get(i),
itemIndex = item.carouselPosition;
if (itemIndex end) {
this.remove(item, true);
changed = true;
}
else {
i++;
}
}
// function to create a card and add to the carousel
var createCard = function(carouselPos, layoutPos) {
var card = this.createItem(i);
if (card) {
card.carouselPosition = carouselPos;
if (layoutPos != null) {
this.insert(layoutPos, card);
}
else {
this.add(card);
}
if (carouselPos == index) {
activeCard = card;
}
changed = true;
}
};
// add new items
if (items.length) { // if existing items, add to the left and right
var first = items.first().carouselPosition,
last = items.last().carouselPosition;
for (var i = first-1; i>=start; i--) {
if (i >= 0) {
createCard.call(this, i, 0);
}
}
for (var i = last+1; i<=end; i++) {
createCard.call(this, i);
}
}
else { // if no existing items, just add cards
for (var i = start; i= 0) {
createCard.call(this, i);
}
}
}
// if changed, make sure the layout is updated
// also, update the active item if needed
if (changed) {
this.doLayout();
var activeItem = this.layout.getActiveItem();
if (activeCard && activeItem != activeCard) {
this.layout.setActiveItem(activeCard);
}
}
}
Получение данных и кэширование
ShopStyle предоставляет API которое позволяет получать и фильтровать товары из категории. Так же есть возможность получения частей данных что необходимо для реализации постраничного отображения. Разработчикам хотелось иметь непосредственный доступ к данным, а так же избежать проблем вызванных получением данных из сети, а это означало кэшерование изображений.
Для этих целей был создан класс DataCache для упрощения получения данных и кеширования данных о товарах. в своей основе DataCache содержит простую функцию “getItems” которая принимает диапазон товаров а так же функцию для обратного вызова для обработки данных о товарах после их получения, так же она имеет некоторую простую обработку для избежания идентичных запросов и непосредственно возвращает данные которые уже были получены. В результате кеширование становится элементарным — все что необходимо так это вызвать getItems с диапазоном товаров. Этот процесс изображен на диаграмме:
Когда getItems вызывается для первых 100 элементов — отправляется запрос в ShopStyle. При последующих запросах getItems для элементов 1-10 и 11-20 приложение определяет что эти данные уже запрашиваются и не посылает дополнительные запросы в API. Когда приходит ответ вызываются соответствующий функции обратного вызова. При последующем обращении к getItems для элементов 21-30, сразу же идет вызов обратной функции так как данные уже были получены.
XTemplate
При отображении товаров каждая страница отображает 8 или 9 (в зависимости от ориентации) элементов в grid layout. В большинстве случаев используются плавающие элементы но разработчики захотели пойти несколько другим путем и использовать возможности CSS3:
SS.PagedCarousel.Indicator = Ext.extend(Ext.Component, {
baseCls: "ss-pagedCarousel-indicator",
initComponent: function() {
if (this.carousel.rendered) {
this.render(this.carousel.body);
}
else {
this.carousel.on('render', function() {
this.render(this.carousel.body);
}, this, {single: true});
}
},
onRender: function() {
SS.PagedCarousel.Indicator.superclass.onRender.apply(this, arguments);
this.positionIndicator = this.el.createChild({tag: 'span'});
},
onBeforeCardSwitch: function(carousel, card) {
if (card) {
var position = card.carouselPosition/(this.carousel.itemCount-1),
position = isNaN(position) ? 0 : position*100,
el = this.el;
this.positionIndicator[this.carousel.direction=='vertical'?'setTop':'setLeft'](position.toFixed(2)+"%");
el.setStyle('opacity', '1');
if (this.hideTimeout != null) {
clearTimeout(this.hideTimeout);
}
this.hideTimeout = setTimeout(function() {
el.setStyle('opacity', '0');
}, 1500);
}
},
});
Мобильные интернеты
Touch версия приложения не является полной копией оригинального приложения — например была реализована возможность поиска в то время как оригинальное приложение использует механизм фильтров. Все это демонстрирует преимущества Sencha Touch при создании аналогов приложений доступных на мобильных платформах, а так как это все таки интернет приложение то оно будет работать и на WebOS и на Android (сразу после того как разработчики допилят соответствующую поддержку в библиотеке) из коробки.
Ну и в заключении автор оригинальной статьи благодарит Brian Sugar и Trey Matteson из Sugar за предоставление доступа к API, а так же в консультировании по профильным вопросам и желает им всего.