Как стать автором
Обновить

ShopStyle

Время на прочтение7 мин
Количество просмотров688
Автор оригинала: James Brantly
По неясным причинам запись исчезла из официального блога через несколько часов после публикации, а так же убран контент с демо сайта. Позже запись в блоге появилась вновь, но с сообщением о том что приложение будет доступно в ближайшее время

Сегодня команда разработчиков 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, а так же в консультировании по профильным вопросам и желает им всего.
Теги:
Хабы:
Всего голосов 11: ↑6 и ↓5+1
Комментарии3

Публикации

Истории

Ближайшие события