日記ブログ、または雑多なメモ
2014年1月12日

埋め込みギャラリー続編/画像のlazyload実装(javascript)






 (この日の埋め込みギャラリーはさらに改造し、最新版は次の日分に掲載)

 先日、参考になる~と書いたページを参考に組もうとしたが、lazy loadingは意外とあっさり組み込めたものの、その他をまとめるのはかな~~り時間がかかりそうなので自分でいちから作るのはあきらめた。

 で、swipeshowの表示部分にlazyloadさせるコードを入れてみたらうまく動いた。


IE以外は。


 うーん。 先頭画像以降のimgタグの中のsrcをsrclazyとし、表示前にsrcに書き換えて逐次ロードするという方式なのだが、IEの場合、正規のsrcがないとスクリプト自体が動かない…よくわからないな。


 それはともかく。
よくよく考えたらswipeshowはドットボタンを押して任意の画像まで一気にスクロールする機能があったことに気づいた。
これではlazyload組み込んだらスキップされてる画像は読み込まれないままだ。 うーん、まあ、とりあえず動くようにしてみよう。


 で、IEが正規のsrcがないと動かない件は軽いダミー画像をsrcにしておくことで解決。
すると別の問題発現。 IEとseamonkeyではURL入れ替え後の画像がダミー画像の縦横比で表示される。

 うーん…なんか、おまじないが必要っぽいので、URL書き換え後の画像のサイズを取得後、 replaceChildしてみたらすっぽり収まった。
 
  var nextImage = document.getElementById("image" + (idx));
  if (nextImage) {
    if (nextImage.getAttribute("srclazy")) {
      nextImage.setAttribute("src", nextImage.getAttribute("srclazy"));
      var rewImage = document.getElementById("image" + (idx));
      var orgX = rewImage.naturalWidth;
      var orgY = rewImage.naturalHeight;
      //console.log(orgX,orgY);
      rewImage.style.width = orgX;
      rewImage.style.height = orgY;
      var rewImage_ = rewImage.cloneNode(true);
      rewImage.parentNode.replaceChild(rewImage_,nextImage);
    }
  }


追加したコード。 idxはswipeshowの現在画像のid番号。
replaceChildするときはコピー元をクローンしておかないとだめらしい。
打ち消し線部分いらないこと判明。 むしろ、あるとキャッシュがないときにサイズが0x0になって表示されなくなる。


 <div class="slideshow swipeshow preventSel">
    <ul class="slides">
      <li class="slide">
        <div class="mypopup" rel="ugallery_cvt/1-big.jpg"><img id = "image0" src="ugallery_cvt/1.jpg" alt="" /></div>
      </li>
      <li class="slide">
        <div class="mypopup" rel="ugallery_cvt/2-big.jpg"><img id="image1" src="dammy.jpg" srclazy="ugallery_cvt/2.jpg" alt="" /></div>
      </li>
      <li class="slide">
        <div class="mypopup" rel="ugallery_cvt/3-big.jpg"><img id="image2" src="dammy.jpg" srclazy="ugallery_cvt/3.jpg" alt="" /></div>
      </li>
      <li class="slide">
        <div class="mypopup" rel="ugallery_cvt/4-big.jpg"><img id="image3" src="dammy.jpg" srclazy="ugallery_cvt/4.jpg" alt="" /></div>
      </li>
      <li class="slide">
        <div class="mypopup" rel="ugallery_cvt/5-big.jpg"><img id="image4" src="dammy.jpg" srclazy="ugallery_cvt/5.jpg" alt="" /></div>
      </li>
      <li class="slide">
        <div class="mypopup" rel="ugallery_cvt/6-big.jpg"><img id="image5" src="dammy.jpg" srclazy="ugallery_cvt/6.jpg" alt="" /></div>
      </li>
      <li class="slide">
        <div class="mypopup" rel="ugallery_cvt/7-big.jpg"><img id="image6" src="dammy.jpg" srclazy="ugallery_cvt/7.jpg" alt="" /></div>
      </li>
    </ul>
    <!--<button class='previous'></button>
    <button class='next'></button>-->
    <div class='dots'></div>
  </div>


HTML側。
imgタグ内にハメ殺しの「image+番号」のidを付け、2番目以降の画像はsrcをダミー画像に、srclazyというタグに実際のURLを入れておく。

だいぶ抜けがある気もするが…、一旦とりあえずこれで行こう。


あとは…<noscript>を入れてなかったので入れとかんと。 (いまさら






 ……ええい、ついでなので読み込み中画面表示も作ってしまえ。
*swipwshowのスクリプト初期化部にて、位置調整用div+ローディング画像をappendしてオーバーレイ表示の準備。 それぞれopacityを0に
*swipeshowの各スライド処理部にて、本体画像のsrclazyをsrcに書き換える処理を挿入(画像読み込み開始)
*オーバーレイ表示のopacityを1(フェードイン)に、本体画像imgのopacityを0(非表示)に設定(ローディング中)
*読み込み完了
*オーバーレイ表示のopacityを0に(フェードアウト)。 本体画像のopacityを1に(フェードイン)

という流れで。
append部分は「汚いソースだなぁ」なので割愛。
HTMLの構造をなるべくいじりたくなかったので、スライド表示枠である親divにidを付けてアペンドしていく。

問題は本体画像の読み込み完了をどう取得するかだが、
IEは「attachEvent」、その他のブラウザは「addEventListener」のloadを使ってフックしたらいけた。
      function loadOver() {
        console.log("loaded");
        var rewImage = document.getElementById("image" + (idx));
        rewImage.style.opacity = "1";
        lImg1.style.opacity = "0";
        lImg.style.opacity = "0";
      }
      function addEv(obj, type, func){
        if(obj.addEventListener){ obj.addEventListener(type, func, false); }
        else{ if(obj.attachEvent) obj.attachEvent('on' + type, func); }
      }

      addEv(rewImage,'load', loadOver);


IEとその他で処理系が違うので振り分ける。
load(読み込み完了)イベントが発生したら、読み込み完了後の処理関数loadOverを起動する。 と。
自分のコードでは本体画像とローディング画像表示のopacity変更をさせている。

で、ここに一つ罠が。
このままだとIEでは画像を読み込み終わってもloadイベントが発火しない模様。
細かいことはよくわからんが、とにかくsrcの設定を最後にしないといけないらしい。
自分のコードの場合、

*srclazyー>srcに書き換えて読み込み
*addEvでオブジェクトにイベントをくっつけ
*再度srcを書き換え

の順番にしたら動いた。


 とか、こんなことをしつつ、このaddEventしたイベントはリムーブしなくていいのだろうか、
とかよくわかっていなかったりする。 とりあえず動いているのでいいとしよう。
javascriptに詳しい知り合いが欲しいぜぇ~……


とりあえず、埋め込みギャラリーでやりたいことはやりつくしたので、
これで完了とする。



完了してなかった。
若干抜けがあったのと、not foundに対応したのと、eventlistenerを使うのをやめたバージョンに書き換え。
  var nextImage = document.getElementById("image" + (idx));

  if (nextImage  ) {
    if (nextImage.getAttribute("srclazy")) {
      nextImage.setAttribute("src", nextImage.getAttribute("srclazy"));
      var rewImage = document.getElementById("image" + (idx));
      lImg1.style.opacity = "0";
      lImg.style.opacity = "0";
      nextImage.onerror = function (evt) { 画像がnot foundならローディング中表示化
        lImg1.style.opacity = ".65";
        lImg.style.opacity = "1";
      }

      if ( !rewImage.style.opacity ) { // src書き換えが済んでないので表示初期化
        rewImage.style.opacity = "0";
        lImg1.style.opacity = ".65";
        lImg.style.opacity = "1";
      }

      var rewImage_ = rewImage.cloneNode(true);
      rewImage.parentNode.replaceChild(rewImage_,nextImage);

      function loadOver() {
        //console.log("loaded");
        var rewImage = document.getElementById("image" + (idx));
        rewImage.style.opacity = "1";
        lImg1.style.opacity = "0";
        lImg.style.opacity = "0";
      }
      rewImage.onload = loadOver; // 読み込み完了なら後処理関数呼び出し
      nextImage.setAttribute("src", nextImage.getAttribute("srclazy")); // IE用おまじない
    }
  }


汚いコードだなぁ。

サンプルはこちら (deleted)
画像の1枚目はわざとnotfoundにしてあります。

lImg1.style.opacity
lImg.style.opacity
…の2つはオーバーレイ表示の文字部分とローディングgif部分。
画像が「not found」なら「ロード中」表示ってのもどうなんだっちゅう話だが、とりあえずこれで置いておく。
本当においておく!



最後にまとめ。 念のためソースの場所を。
jquery.swipeshow.min.js (deleted) オリジナル
jquery.swipeshow.min-c.js (deleted) 今回の改造版
「待機中」画像 (deleted)
「ローディングくるくる」画像 (deleted)
あと、css
.imgfade {
  transition: all 0.2s ease;
  -moz-transition: all 0.2s ease;
  -webkit-transition: all 0.2s ease;
  -o-transition: all 0.2s ease;
  -ms-transition: all 0.2s ease;
}
.slideBoxnotice {
  margin-top:40px;
 
}
.slideBoxloader {
  width : 10%;
  margin: 0 auto;
}


HTML側は
 <div class="slideshow swipeshow preventSel" id="slideBox">
    <ul class="slides" >
      <li class="slide">
        <div class="mypopup" rel="ugallery_cvt/1-big.jpg"><img class="imgfade" id ="image0" src="dammy.png" srclazy="ugallery_cvt/1.jpg" alt="" /></div>
      </li>
      <li class="slide">
        <div class="mypopup" rel="ugallery_cvt/2-big.jpg"><img class="imgfade" id="image1" src="dammy.png" srclazy="ugallery_cvt/2.jpg" alt="" /></div>
      </li>
      <li class="slide">
        <div class="mypopup" rel="ugallery_cvt/3-big.jpg"><img class="imgfade" id="image2" src="dammy.png" srclazy="ugallery_cvt/3.jpg" alt="" /></div>
      </li>
      <li class="slide">
        <div class="mypopup" rel="ugallery_cvt/4-big.jpg"><img class="imgfade" id="image3" src="dammy.png" srclazy="ugallery_cvt/4.jpg" alt="" /></div>
      </li>
      <li class="slide">
        <div class="mypopup" rel="ugallery_cvt/5-big.jpg"><img class="imgfade" id="image4" src="dammy.png" srclazy="ugallery_cvt/5.jpg" alt="" /></div>
      </li>
      <li class="slide">
        <div class="mypopup" rel="ugallery_cvt/6-big.jpg"><img class="imgfade" id="image5" src="dammy.png" srclazy="ugallery_cvt/6.jpg" alt="" /></div>
      </li>
      <li class="slide">
        <div class="mypopup" rel="ugallery_cvt/7-big.jpg"><img class="imgfade" id="image6" src="dammy.png" srclazy="ugallery_cvt/7.jpg" alt="" /></div>
      </li>
    </ul>
    <!--<button class='previous'></button>
    <button class='next'></button>-->
    <div class='dots'></div>
  </div>

  <script>
    (function($) {
      $(".version").text($.swipeshow.version);
      $(".slideshow").swipeshow({ mouse: true, interval: 6000 });
    })(jQuery);
  </script>

赤字が今回の改造に関する書き換え
青字は前回組み込んだfancyboxポップアップ用の書き換え

こんな感じで。




コメント欄
(投稿なし)

コメントなどありましたらこちらからどうぞ
名前
内容
 ※名前、内容ともに入力必須です
- C'sGallery Blogっぽく見えるシステム3.2 -
小武 (管理人) eta2@tim.hi-ho.ne.jp