不明な理由により、公開後数時間でエントリが公式ブログから消え、デモサイトのコンテンツも削除されました。 その後、ブログエントリが再び表示されましたが、近いうちにアプリケーションが利用可能になるというメッセージが表示されました
本日、Sencha開発チームは、ライブラリに基づいた新しいデモアプリケーション
ShopStyleのリリースを発表しました。 ShopStyleは、PopSugarポータルの一部であるクラシックなiPhoneおよびiPadアプリです。 提示されたアプリケーションは、Sencha Touchライブラリで開発され、革新の1つであるTouch Carouselを使用しています。 特に、Sencha Touchの一部である新機能の1つである「エンドレスカルーセル」が紹介されています。 このコンポーネントの最も重要な機能はアクティブなDOM管理です。これにより、アプリケーションはiPadに存在するメモリ制限に適合できます。
もちろん、サイトのソースコードを調べることもできます。この記事では、このアプリケーションを作成する上で最も興味深い技術的な点を検討します。 主な問題は、数千の製品が1つのカテゴリに含まれることがあることです。 これらすべてのデータを一度にブラウザのメモリにダウンロードすることは、保証されたファイルです。
カルーセルの作成
カルーセルは、データを表示するスライド表示領域を使用して、数千のアイテムを処理できます。 現在のページには、現在、前、次の3つのコンテンツが含まれる領域が作成されます。 ユーザーが対応する領域をめくると、それらが作成および破棄され、コンテンツが現在の状態に対応するようになります。 このため、実際の数が膨大になる可能性があるにもかかわらず、カルーセル内のいつでも要素の数がかなり少ないことを保証することが可能です。 次の図では、スライド領域は3ページで構成されています。 3番目のページが最初にフォーカスされ、2番目から4番目のページが初期化されます。 ユーザーが4番目のページに移動すると、アクティブ領域が右に移動し、2番目のページも削除されて5番目のページが作成されます。
カルーセルの初期化は基本的です。
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にリクエストが送信されます。 エレメント1-10および11-20に対する後続の
getItemsリクエストでは、アプリケーションはこのデータがすでにリクエストされていると判断し、追加のリクエストをAPIに送信しません。 応答が到着すると、対応するコールバック関数が呼び出されます。 要素
21〜30のgetItemsの次の呼び出しは、データが既に受信されているため、すぐに逆関数を呼び出します。
XTemplate
製品を表示する場合、各ページには、グリッドレイアウトに8または9(方向に応じて)要素が表示されます。 ほとんどの場合、フローティング要素が使用されますが、開発者は少し異なるパスを取り、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);
}
},
});
モバイルインターネット
アプリケーションのタッチバージョンは、元のアプリケーションの完全なコピーではありません-たとえば、元のアプリケーションがフィルターメカニズムを使用している間に検索オプションが実装されました。 これはすべて、モバイルプラットフォームで利用可能なアプリケーションの類似物を作成する際のSencha Touchの利点を示しています。これはまだインターネットアプリケーションであるため、WebOSとAndroidの両方で動作します(開発者がライブラリで対応するサポートを終了した直後)。
結論として、元の記事の著者は、APIへのアクセスを提供してくれたSugarのBrian SugarとTrey Mattesonに感謝するとともに、関連する問題について助言してくれて、すべてを願っています。