先讲一下功能需求,很简单:
我们需要在鼠标放上用户头像的时候,打开一个扩展层,显示一些用户的扩展信息
如图:
好像这个功能和延迟读取没有什么关系,细想一下,当页面上用户的头像比较多,而且比较集中的时候,你鼠标很有可能会不停的划过它们,那要是一放上去就执行程序,势必会引起很多困扰,因为你也许根本不想去操作它,要是它的加载又影响到你其它的操作,是不是很烦人。所以这样的延迟读取是非常有必要的,哪怕只是延迟半秒种,都会有很好的效果。
那现在分解一下这个过程:
- 将鼠标指向一个用户的头像
- 触发onmouseover
- 触发setTimeout
- 延迟时间之后,执行加载程序,打开扩展层
- 鼠标移出扩展层
- 隐藏该扩展层
这个过程很清晰,但用户不可能这么听话的等着它进行,还有一个过程是这样的:
- 将鼠标指向一个用户的头像
- 很快又离开了用户的头像
其实还有个过程是这样的:
- 将鼠标指向一个用户的头像
- 很快又指向另一个用户的头像
- …
其实第二和第三种情况,在加上延迟处理后,就能比较好的得到解决。
思路:
- 在头像的img标签里加上特殊的class,如:faceinfo,这样可以遍历faceinfo来达到给所有头像加上这个功能
- 再给头像的img标签加上rel=’{UID}’,如:rel=’5′,这个数字是用户的ID,程序根据这个用户ID来读取用户的扩展数据
遍历class=’faceinfo’的元素
$('.faceinfo').each();
鼠标放上头像后,如果用触发onmouseover,那些造成一个问题,【冒泡问题】,因为打开的扩展层里包含了很多的其它元素,当鼠标在上面移动的时候,立刻就会触发扩展层的onmouseout事件,那扩展层就关闭了,效果很不好,所以这里要用jQuery的mouseenter(),而且还要加上unbind(‘mouseenter’)
$(this).unbind('mouseenter').mouseenter()
触发之后,利用AJAX来读取用户扩展信息,但要先获得用户ID,ID放在img 标签的rel里,所以
var rel=_showthis.attr('rel');
发送AJAX请求
$.get(domain+"m/space/getUserInfo/uid="+rel,{},function(result){});
这是几个主要的东西,在这个过程中,还有需要一些效果,如:需要一个加载效果,那么在进行AJAX请求之前,打开加载的动画,当AJAX请求结束后,关闭这个动画。
打开加载动画
f_create_loading('create',_top,_left,'','');
这个函数有5个参数,第1个有两个值,create和remove,意思很明显,创建了,也要移除它。第2个和第3个是它显示的坐标,第4个是显示文本,第5个是指定位置,如top,left,right,bottom。完整代码:
function f_create_loading(action,top,left,text,position){
if(action=='remove'){
if($('#floading')){
$('#floading').remove();
}
return;
}
var text=text?text:'';
var _position=position?position:'';
var _top;
var _left;
if(_position=='bottom'){
_top=top+30;
_left=left;
}
if(_position=='top'){
_top=top-28;
_left=left;
}
if(_position==''){
_top=top;
_left=left-28;
}
var div = "<div id='floading' style=\"text-align:center;position:absolute;top:"+_top+"px;left:"+_left+"px;z-index:10002;\"><img src=\""+domain+"images/loading_photo.gif\" style=\"width:28px;\" align=\"absmiddle\" /> "+text+"</div>";
$(document.body).append(div);
}
很简单,利用jQuery的append(),将加载动画层加入到body里,并根据坐标及位置显示。action==’remove’的时候,进行了ID检测,如果检测到#floading,则移除它。
加载动画的坐标利用头像的坐标来获取,所以在开始,需要获取头像的坐标
var opt=_showthis.offset();
var _top=opt.top;
var _left=opt.left;
考虑同一用户头像,只读取一次数据,之后就直接隐藏显示扩展层就好了,所以需要设定不同用户的扩展层ID,这里就用用户ID加字符串的形式
var id=rel+'_faceinfo';
为了实现这个效果,在创建各用户扩展层的时候,为每个层增加了一个class=’face_div’,这样在进行加载的时候,先判断这个扩展层是不是已经存在,如果存在,只需要移动它到目标位置即可,如果不存在,那么执行加载程序,并创建它的扩展层
if($('#'+id).attr('class')=='face_div'){ //如果该ID的DIV已经存在
showThisFace(rel,_top-10,_left-10); //直接调整该ID DIV的坐标并显示
}
创建扩展层的函数
function create_face_div(id,_top,_left,w,h){
_left=checkClientW(_left);
var div = "<div id='"+id+"' class=\"face_div\" style=\"text-align:center;position:absolute;top:"+_top+"px;left:"+_left+"px;z-index:10001;width:"+w+"px;border:1px solid #ccc;background-color:#fff;\"></div>";
$(document.body).append(div);
}
同样,它用了创建加载效果一样的方法append。它也有5个参数,id是要创建扩展层的ID,由前面生成,_top和_left为坐标,w和h为宽高。接下来有一句:_left=checkClientW(_left);这个是用以检测创建的扩展层是不是会移出到屏幕的外面,如果是减少_left,不至于浏览器出现横向滚动条。checkClientW()函数:
function checkClientW(_left){
var clientWH=getclientWH();
if(_left+304>clientWH[0]){
_left=_left-204;
}
return _left;
}
它首先获取浏览器可视范围的宽度,getclientWH(),它返回宽高,然后判断头像所在横坐标加上扩展层的宽度是否超过了浏览器可视范围的宽度,如果是,则减去一个值,然后将新的_left返回,如果不是直接返回_left。getclientWh()函数:
function getclientWH(){
return [document.documentElement.clientWidth,document.documentElement.clientHeight];
}
完整的主要处理函数:showFaceinfo()
function showFaceInfo(){
var faceinfo;
$('.faceinfo').each(function(){
$(this).unbind('mouseenter').mouseenter(function(){
var _showthis=$(this);
faceinfo=setTimeout(function(){
var opt=_showthis.offset(); //取得当前元素的坐标
var _top=opt.top;
var _left=opt.left;
var rel=_showthis.attr('rel'); //取得当前元素的rel值,这里是存放的用户UID
var id=rel+'_faceinfo';
$('.face_div').hide(); //隐藏所有class='face_div'的元素
if($('#'+id).attr('class')=='face_div'){ //如果该ID的DIV已经存在
showThisFace(rel,_top-10,_left-10); //直接调整该ID DIV的坐标并显示
}else{
if(faceid==true){ //faceid用以判断加载程序是否完成
faceid=false; //将faceid置为false
f_create_loading('create',_top,_left,''); //创建加载效果
$.get(domain+"m/space/getUserInfo/uid="+rel,{},function(result){ //AJAX
create_face_div(id,_top-10,_left-10,304,146); //创建加载层
$('#'+id).html(result); //将返回的结果写入加载层
f_create_loading('remove',opt.top,opt.left,''); //移除加载效果
faceid=true; //将faceid置为true
});
}
}
},700);
});
$(this).mouseleave(function(){
clearTimeout(faceinfo);
});
});
}
mouseleave();用来处理鼠标离开头像时,停止setTimeout()的执行。有了这个后,当鼠标快速在头像上移动的时候,就不停的触发mouseenter()和mouseleave(),加载程序就没有执行,只有当鼠标在头像上停留700毫秒的时候,才会执行加载程序,除了取得坐标及用户ID外,程序首先会判断该用户的扩展信息层是否已存在,如果存在,说明已经加载过,不需要再加载了,只需要将扩展层移到现在的位置。
function showThisFace(id,_top,_left){
_left=checkClientW(_left);
$('#'+id+'_faceinfo').css('top',_top);
$('#'+id+'_faceinfo').css('left',_left);
$('#'+id+'_faceinfo').show();
}
如果没有,就要继续执行加载程序。但是,如果已经在执行加载的时候,鼠标又移到另一个头像上,那程序会判断faceid的值,如果不为真,就不会执行新的加载,继续加载前一个用户的扩展信息,执行完后,将faceid置为true。如果faceid==true,那先将faceid=false,执行加载程序。