一个 YUI模块,Gallery

学习一个框架到一定阶段后,如果希望对它有更深入的理解,应该尝试写给它写独立的模块或者插件。

趁周末写了一个YUI模块:

1.支持自定义数量的预加载

2.支持history

3.支持键盘导航

 

参照了人人网的相册,还有百度的图片搜索结果页面。

人人网的相册功能,体验还是不错的。载入大图的时候速度很快,猜测肯定是预加载了的,现在的网站大规模的使用了ajax功能,url不会刷新,但是内容会变,带来的后果就是,可能失去历史信息,人人的相册对这个也是做了处理的,图片切换url地址会变,那么历史前进后退功能也就没有问题了。而且也是支持鼠标导航的。试下左右方向键。

类似的效果还有百度的图片搜索结果,有一个很贴心的功能就是点击向下翻页的时候,上一页的最后一个会列在新一页的第一个,这样感觉很好,这个一并copy了

1.图片预加载

最简单能想到的就是 

var img = new Image();

img.src = imgurl;

对IE浏览器来说,很好,但是火狐却不能达到预加载的目的。【我自己没有验证,参考了这里 ,因为火狐中的图片有独立的缓存 new Image().src  has a separate cache for images】

一个兼容的预加载的实现就是

    preloadImage:function(src){
      Y.log('preload:'+src);
      if(Y.UA.ie){
        new Image().src = src;
      }else{
        var d = document,
        b = document.body;
        o = d.createElement('object');
        o.data  = src;
        o.width = o.height = 0;
        b.appendChild(o);
      }
    }

 

2.历史记录功能

YUI3 是提供了这样的功能的:当切换一张图片,改变url的hash值,即历史记录添加一个value

 history.addValue("pic",currentIndex || null);

 

切换图片后,重新刷新页面,或者将本页面的url发送给别人,再次进入这个页面,图片的也是如期望所显示的

        var pic = Number(history.get("pic"));
        if(thumbs.item(pic)){
          gallery.gotoIndex(pic);
        }

3.键盘导航

键盘导航还是比较简单的,给document添加一个keydown 事件,判断如果按下的是左方向键,那么久显示上一张图片,如果按下的是向右方向键,那么显示下一张图片。按理说,应该也是可以将事件绑定到document.body 上的,发现在出FF以外的浏览器上是OK的,而FF不太灵敏,最终将keydow 事件绑定到了document上。

        var eventType = (Y.UA.webkit || Y.UA.ie) ? 'keydown' : 'keypress';
        var handleKeypress = function(e){
          //console.log('keynav',e.keyCode);
          if(e.keyCode === 37 || e.keyCode === 38){
            gallery.prevImage();
          }else if(e.keyCode === 39 || e.keyCode === 40){
            gallery.nextImage();
          }
        }

  

第一个YUI模块还是不够满意,放了好多代码在实例化后,来支持历史记录和键盘导航功能,有空会将这些逻辑放到模块本身中去。上代码了:

<!doctype html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <meta name="keywords" content="keyword1,keyword2,keyword3"> <meta name="description" content="some sentences"> <link rel="stylesheet" charset="utf-8" href="http://k.kbcdn.com/k2/css/reset-1-0-0.css"> <!--start: for iOS--> <link rel="apple-touch-icon" href="http://k.kbcdn.com/product/common/header/fav.png"> <!--end : for iOS--> <style> .k2-fix-float:after{content:"\0020";display:block;height:0;clear:both}.k2-fix-float{*zoom:1} #img-con{border:1px solid #999;height:500px;} #thumbs {width:415px;height:75px;margin:0 auto;overflow:hidden;position:relative;} #thumbs ul{position:relative;padding-left:20px;margin-right:-999999em;} #img-el{background:url(http://loadinggif.com/images/image-selection/3.gif);} #nextbatch,#prevbatch,#thumbs ul,#thumbs li{float:left;} #nextbatch,#prevbatch{position:absolute;display:inline-block;width:20px;z-index:1;height:100%;} .enable{background:blue;color:black;} .disabled{background:gray;} #prevbatch{left:0} #nextbatch{right:0;}; /* fuck ie */ </style> <title>gallery</title> </head> <body> <div id="indicator"> &nbsp; </div> <div id="thumbs" class="thumbs k2-fix-float"> <a href="javascript:;" id="prevbatch" class="enable">&lt;&lt;</a> <ul class="k2-fix-float"> <li> <a class="thumb" href="http://farm4.static.flickr.com/3261/2538183196_8baf9a8015.jpg" title="Title #0"> <img src="http://farm4.static.flickr.com/3261/2538183196_8baf9a8015_s.jpg" alt='1'/> </a> </li> <li> <a class="thumb" href="http://farm3.static.flickr.com/2404/2538171134_2f77bc00d9.jpg" title="Title #1"> <img src="http://farm3.static.flickr.com/2404/2538171134_2f77bc00d9_s.jpg"/> </a> </li> <li> <a class="thumb" href="http://farm4.static.flickr.com/3261/2538183196_8baf9a8015.jpg" title="Title #0"> <img src="http://farm4.static.flickr.com/3261/2538183196_8baf9a8015_s.jpg" alt='1'/> </a> </li> <li> <a class="thumb" href="http://farm3.static.flickr.com/2404/2538171134_2f77bc00d9.jpg" title="Title #1"> <img src="http://farm3.static.flickr.com/2404/2538171134_2f77bc00d9_s.jpg"/> </a> </li> <li> <a class="thumb" href="http://farm4.static.flickr.com/3261/2538183196_8baf9a8015.jpg" title="Title #0"> <img src="http://farm4.static.flickr.com/3261/2538183196_8baf9a8015_s.jpg" alt='1'/> </a> </li> <li> <a class="thumb" href="http://farm3.static.flickr.com/2404/2538171134_2f77bc00d9.jpg" title="Title #1"> <img src="http://farm3.static.flickr.com/2404/2538171134_2f77bc00d9_s.jpg"/> </a> </li> <li> <a class="thumb" href="http://farm4.static.flickr.com/3261/2538183196_8baf9a8015.jpg" title="Title #0"> <img src="http://farm4.static.flickr.com/3261/2538183196_8baf9a8015_s.jpg" alt='1'/> </a> </li> <li> <a class="thumb" href="http://farm3.static.flickr.com/2404/2538171134_2f77bc00d9.jpg" title="Title #1"> <img src="http://farm3.static.flickr.com/2404/2538171134_2f77bc00d9_s.jpg"/> </a> </li> <li> <a class="thumb" href="http://farm4.static.flickr.com/3261/2538183196_8baf9a8015.jpg" title="Title #0"> <img src="http://farm4.static.flickr.com/3261/2538183196_8baf9a8015_s.jpg" alt='1'/> </a> </li> <li> <a class="thumb" href="http://farm3.static.flickr.com/2404/2538171134_2f77bc00d9.jpg" title="Title #1"> <img src="http://farm3.static.flickr.com/2404/2538171134_2f77bc00d9_s.jpg"/> </a> </li> <li> <a class="thumb" href="http://farm4.static.flickr.com/3261/2538183196_8baf9a8015.jpg" title="Title #0"> <img src="http://farm4.static.flickr.com/3261/2538183196_8baf9a8015_s.jpg" alt='1'/> </a> </li> <li> <a class="thumb" href="http://farm3.static.flickr.com/2404/2538171134_2f77bc00d9.jpg" title="Title #1"> <img src="http://farm3.static.flickr.com/2404/2538171134_2f77bc00d9_s.jpg"/> </a> </li> <li> <a class="thumb" href="http://farm3.static.flickr.com/2093/2538168854_f75e408156.jpg" title="Title #2"> <img src="http://farm3.static.flickr.com/2093/2538168854_f75e408156_s.jpg"/> </a> </li> <li> <a class="thumb" href="http://farm4.static.flickr.com/3261/2538183196_8baf9a8015.jpg" title="Title #0"> <img src="http://farm4.static.flickr.com/3261/2538183196_8baf9a8015_s.jpg" alt='1'/> </a> </li> <li> <a class="thumb" href="http://farm3.static.flickr.com/2404/2538171134_2f77bc00d9.jpg" title="Title #1"> <img src="http://farm3.static.flickr.com/2404/2538171134_2f77bc00d9_s.jpg"/> </a> </li> <li> <a class="thumb" href="http://farm3.static.flickr.com/2093/2538168854_f75e408156.jpg" title="Title #2"> <img src="http://farm3.static.flickr.com/2093/2538168854_f75e408156_s.jpg"/> </a> </li> <li> <a class="thumb" href="http://farm3.static.flickr.com/2404/2538171134_2f77bc00d9.jpg" title="Title #1"> <img src="http://farm3.static.flickr.com/2404/2538171134_2f77bc00d9_s.jpg"/> </a> </li> </ul> <a href="javascript:;" id="nextbatch" class="enable">&gt;&gt;</a> </div> <div id="img-con"> <img id="img-el" src="http://loadinggif.com/images/image-selection/3.gif"/> </div> <div id="next-prev"> <a id="prev" href="javascript:;">prev</a> <a id="next" href="javascript:;">next</a> </div> <script src="http://yui.yahooapis.com/3.3.0/build/yui/yui-min.js"></script> <script type="text/javascript"> YUI({ //filter:'debug', combine:false, modules:{ 'k2-gallery':{ fullpath:'http://files.cnblogs.com/wewe/gallery.js', requires:['oop','base-base','node-base','anim-base'] } } }).use("k2-gallery","anim","history",function(Y){ var batchsize = 5, datasource = Y.one("#thumbs>ul"), SINGLE_WIDTH = 75, thumbs = datasource.all("li>a>img"), total = thumbs.size(), currentIndex = 0, slideStartIndex = 0, disabledElement = null, indicator = Y.one('#indicator'), prevBatch = Y.one("#prevbatch"), nextBatch = Y.one("#nextbatch"); var history = new Y.HistoryHash(); //console.log("item:"+item._node); //alert("SINGLE_WIDTH:"+SINGLE_WIDTH); thumbs.setStyle("opacity","0.4"); thumbs.item(currentIndex).setStyle('opacity',"1"); var gallery = new Y.KGallery(datasource,{preloadNumber:5,batchSize:batchsize}), disable = function(el){ el && el.addClass('disabled'); el && (el.disabled = true); }, enable = function(el){ el && el.removeClass('disabled'); el && (el.disabled = false); }, flashHorize = function(horizsize){ var effect = new Y.Anim({ node:datasource, to:{ left:horizsize } }); effect.run(); checkSlide(); }, checkSlide = function(){ //console.log("slideStartIndex:",slideStartIndex,". total:",total); //console.log('disabled element',disabledElement && disabledElement._node); if(slideStartIndex < 2){ disable(prevBatch); } if(slideStartIndex > (total - batchsize)){ disable(nextBatch); } if(slideStartIndex > 2){ if(prevBatch.disabled) enable(prevBatch); } if(slideStartIndex <= (total - batchsize)){ if(nextBatch.disabled) enable(nextBatch); } }; //checkSlide(); gallery.on("change",function(e){ thumbs.item(currentIndex).setStyle('opacity',"0.4"); currentIndex = e.index; thumbs.item(currentIndex).setStyle('opacity',"1"); var distance; if(e.index > 1 && e.index < total){ distance = -(e.index - 1)*SINGLE_WIDTH; slideStartIndex = e.index; }else{ distance = 0; slideStartIndex = 0; } console.log("[EVENT change]","index:",e.index,"slideStartIndex:",slideStartIndex,"total:",total,"batchsize:",batchsize,"SINGLE_WIDTH:",SINGLE_WIDTH,"flash start...","distance is :",distance); flashHorize(distance); //history surport history.addValue("pic",currentIndex || null); indicator.set("innerHTML",(currentIndex+1)+"/"+total); }); var pic = Number(history.get("pic")); if(thumbs.item(pic)){ gallery.gotoIndex(pic); } Y.on('history:change', function (e) { //alert('changed'); if(e.src === Y.HistoryHash.SRC_HASH){ pic = Number(history.get("pic")); //console.log("pic:",pic); if(thumbs.item(pic)){ gallery.gotoIndex(pic); } } }); var eventType = (Y.UA.webkit || Y.UA.ie) ? 'keydown' : 'keypress'; var handleKeypress = function(e){ //console.log('keynav',e.keyCode); if(e.keyCode === 37 || e.keyCode === 38){ gallery.prevImage(); }else if(e.keyCode === 39 || e.keyCode === 40){ gallery.nextImage(); } } //key nav :bind keydown/keypress to document is better than document.body Y.on(eventType,Y.throttle(handleKeypress,200),document); thumbs.on('click',function(e){ e.halt(); var index = thumbs.indexOf(e.target); index > -1 && index != gallery.currentIndex && gallery.gotoIndex(index); }); //next batch & prev batch nextBatch.on('click',function(){ if(disabledElement === this) return; var num = slideStartIndex + batchsize - 1; if(num > 1 && num < total){ slideStartIndex = num; var distance = -((slideStartIndex -1) * SINGLE_WIDTH); flashHorize(distance); } }); prevBatch.on('click',function(){ if(disabledElement === this) return; var num = slideStartIndex - batchsize +1; if(num > 1 && num < total){ slideStartIndex = num; var distance = -((slideStartIndex -1) * SINGLE_WIDTH); flashHorize(distance); }else if(num <= 0){ slideStartIndex = 0; distance = 0; flashHorize(distance); } }); }); </script> </body> </html>

运行代码

 

YUI.add('k2-gallery', function(Y) {

  var Lang = Y.Lang,
      EVENT_FORWARD = "forward",
      EVENT_BACKWARD = "backward",
      EVENT_CHANGE = "change";


  var DefaultConfig = {
    preloadNumber:10,
    autostart:true,
    playPause:'#play-pause',
    imgContainer:'#img-con',
    imgEl:'#img-el',
    prev:'#prev',
    next:'#next',
    autoPlay:false,
    direction:'forward',
    loading:'#k2-gallery-loading',
    bigImage:{"selector":'li>a','data-src':'href','data-alt':'title'},
    smallImage:{"selector":'li>a>img','data-src':'src','data-alt':'alt'},
    //一批小图个数
    batchSize:5

  };
  function KGallery(imgList,config) {
    Y.log("imgList id:"+imgList);
    //图片源
    this.imageList = Lang.isObject(imgList) ? imgList : Y.one(imgList);
    if(!this.imageList) return;

    this.config = DefaultConfig;

    if(Lang.isObject(config))
      this.config = Y.merge(this.config,config);

    // Y.log(this.config);

    // 图片容器
    this.imgContainer = Y.one(this.config.imgContainer);
    // 图片元素
    this.imgEl = Y.one(this.config.imgEl);
    // next && next trigger
    this.nextEl = Y.one(this.config.next);
    this.prevEl = Y.one(this.config.prev);

    this.bindEvent();

    KGallery.superclass.constructor.call(this);

  }

  KGallery.NAME = 'k2-gallery';
  /*
   * The attributes this extension provides
   */
  KGallery.ATTRS = {
  };

  Y.extend(KGallery,Y.Base,{
    init:function(){
      var self = this;
      Y.log(this.config);
      this.allImages = [];
      this.getAllImages();

      //Y.log(this.allImages.toString());
      if(this.allImages.length > 0)
        this.currentImage = this.allImages[0];

      Y.log("currentImage:"+this.currentImage.toString());
      this.preloadImages();
      this.currentIndex = 0;
      this.showCurrentImage();

      return this;
    },
    bindEvent:function(){
      if(this.nextEl)
        this.nextEl.on("click",this.nextImage,this);
      if(this.prevEl)
      this.prevEl.on("click",this.prevImage,this);

    },
    getAllImages:function(){
      var self = this;
      var bigImages,smallImages;
      bigImages = this.imageList.all(this.config.bigImage.selector);

      bigImages.each(function(v,index){
        if(!self.allImages[index])
          self.allImages[index] = {};
        var obj = self.allImages[index];

        obj.bigSrc = v.getAttribute(self.config.bigImage['data-src']);
        obj.bigAlt = v.getAttribute(self.config.bigImage['data-alt']);

      });
      if(this.config.smallImage.selector){
        smallImages = this.imageList.all(this.config.smallImage.selector);
        smallImages.each(function(v,index){
          if(!self.allImages[index])
            self.allImages[index] = {};
          var obj = self.allImages[index];

          obj.smallSrc = v.getAttribute(self.config.smallImage['data-src']);
          obj.smallAlt = v.getAttribute(self.config.smallImage['data-alt']);
        });
      };

      //console.log(self.allImages.toString());

    },
    preloadImages:function(){
      var currentImage = this.currentImage,
          index = this.currentIndex,
          images = this.allImages.slice(index,index+this.config.preloadNumber),
          len = images.length,
          preloadedFlag = false,
          self = this;
      // Y.log("preload images:"+images.toString());
      Y.each(images,function(v){
        if(!v.preloaded){
          preloadedFlag = true;
          //Y.log("DOES NOT LOADED:"+v.toString());
          self.preloadImage(v.bigSrc);
        }
      });

      preloadedFlag && this.updatePreloadStatus(index,len);
    },
    updatePreloadStatus:function(index,len){
      var item;
      while(len > 0){
        item = this.allImages[index+len-1];
        if(item){
          item.preloaded = true;
          //Y.log("item:"+item.toString());
        }
        --len;
      }
    },
    preloadImage:function(src){
      Y.log('preload:'+src);
      if(Y.UA.ie){
        new Image().src = src;
      }else{
        var d = document,
        b = document.body;
        o = d.createElement('object');
        o.data  = src;
        o.width = o.height = 0;
        b.appendChild(o);
      }
    },
    autoplay:function(){
      var playFn ;
      if(this.config.direction === 'backward')
        playFn = this.next;
      else
        playFn = this.prev;

      if(this.config.autoPlay)
        this.autoPlayTimer = setTimeout(arguments.callee,this.config.duration);
      else
        playFn();
    },
    gotoIndex:function(index){
      var allImage = this.allImages;
      if(index<0){
        index = allImage.length -1;
      }else if(index>allImage.length-1){
        index = 0;
      }
      this.currentIndex = index;
      this.currentImage = allImage[index];
      //console.log("current image",this.currentImage);
      this.showCurrentImage();
      this.fire(EVENT_CHANGE,{currentImage:this.currentImage,index:this.currentIndex});
    },
    nextImage:function(){
      // var allImg = this.allImages;
      // var index = Y.Array.indexOf(allImg,this.currentImage);
      this.gotoIndex(this.currentIndex+1);
    },
    prevImage:function(){
      // var allImg = this.allImages;
      // var index = Y.Array.indexOf(allImg,this.currentImage);
      this.gotoIndex(this.currentIndex-1);
    },
    next:function(){
      Y.log("show next image... ");
      this.setNextImage();
      this.showCurrentImage();

      this.fire(EVENT_FORWARD,{currentImage:this.currentImage});
      this.fire(EVENT_CHANGE,{currentImage:this.currentImage,index:this.currentI});

      if(this.config.autoPlay){
        this.setAutoplayDirection("forward");
        if(!this.autoPlayTimer)
          this.autoPlay();
      }
      this.preloadImages();
    },
    prev:function(){
      this.setPrevImage();
      this.showCurrentImage();
      if(this.config.autoPlay){
        this.setAutoplayDirection("backward");
        if(!this.autoPlayTimer)
          this.autoPlay();
      }
      this.preloadImages();
    },
    setAutoPlay:function(b){
      this.config.autoPlay = !!b;
    },
    setAutoplayDirection:function(d){
      this.config.direction = b;
    },
    showCurrentImage:function(){
      var imgContainer = this.imgContainer,
          imgEl = this.imgEl,
          imgData = this.currentImage;
      if(imgData){
        imgEl.setAttribute("src",imgData.bigSrc);
        imgEl.setAttribute("alt",imgData.bigAlt);
      }
      this.preloadImages();

      /*
      var animOut = new Y.Anim({
        node:node,
        to:{

        }
      });
       */


    },
    /*
     * @param:index
     * @param:offset*/
    getNextBatch:function(index,offset){
      if(offset>this.allImages.length){
        return this.allImages;
      }else{
        var arr = this.allImages.slice(index,offset);
        if(arr.length < offset)
          arr.push(this.allImages.slice(0,offset - arr.length));
        return arr;
      }
    },
    _hideEffect:function(){

    },
    _showEffect:function(){}
  });


  Y.KGallery = KGallery;


},'1-1-0',{requires:['node-base','oop','base-base']});

  

 

 

 

 

 

转载于:https://www.cnblogs.com/wewe/archive/2011/11/19/2255509.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值