ExtJSのGridの列にてイメージを表示しようとした時には、rendererでimgタグを返却する関数を用意したりしますが、imgタグが展開された途端にイメージURLへアクセスしてしまうため、Storeのレコードが大量だった場合には、サーバー側の負荷がかかります。
JavaScriptではいくつか存在する遅延ロードの手法を真似して、Gridのスクロールに適用してみたサンプルです。
特徴としては
- imgタグに、lazyクラスを指定し、本当のURLはdata-url属性に記載
- imgタグのsrcは透過gifを指定
- grid.view.getEl()のscrollイベントをキャプチャ
- getBoundingClientRectにて、Gridの表示領域と、imgの表示領域の絶対座標を取得し、範囲内にあるかどうかを判定
- 範囲内にあれば、imgのdata-url属性の値をsrc属性に設定し、class,data-url属性を削除
# ColumnのRendererで指定する関数
drawImage = (v,opt,rec) ->
url = tmplImage.apply(rec.data)
img = "<img class='lazy' src='data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' data-url='#{url}' style='width:180px'></img>"
return img
createSomething = (store) ->
# グリッドの生成 # Columnのrendererに上記のdrawImageを指定する
grid = Ext.create(
xtype:'grid'
itemdId:'id_of_grid'
store:store
columns: [
{ header:'image' , dataIndex:'url' , width:200 , renderer:drawImage }
]
)
# 遅延ロード処理
lazyLoad = ->
# renderer関数で出力されたimg.lazyの一覧を取得
imgs = grid.view.getEl().select("img.lazy")
# グリッドの絶対座標を取得
gridRect = grid.view.getEl().dom.getBoundingClientRect();
# img.lazy 一覧から、グリッド表示範囲内に表示されているイメージに対して、画像をロードする
for img in imgs.elements
# イメージの絶対座標を取得
imgRect = img.getBoundingClientRect()
# 表示範囲内におさまるかどうか?
if gridRect.top < imgRect.top and imgRect.top < gridRect.bottom
# data-uriに格納されていたイメージへのパスを取得
img.src = img.getAttribute("data-url")
# Imageタグのclassを消去する(次回処理を回避するため)
img.removeAttribute("class")
img.removeAttribute("data-url")
# スクロールイベントにて、遅延ロード処理を行う
grid.view.getEl().on( 'scroll' , lazyLoad)
# 初期表示を行う
setTimeout( lazyLoad , 100)