学习一个框架到一定阶段后,如果希望对它有更深入的理解,应该尝试写给它写独立的模块或者插件。
趁周末写了一个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']});