学习一个框架到一定阶段后,如果希望对它有更深入的理解,应该尝试写给它写独立的模块或者插件。
趁周末写了一个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模块还是不够满意,放了好多代码在实例化后,来支持历史记录和键盘导航功能,有空会将这些逻辑放到模块本身中去。上代码了:
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']});