用jQuery做边栏追随鼠标拖动(思路+实践)

最近自作主张在论坛上做了一个效果,结果被枪毙掉,起因如下:

1.该论坛全站在右边会有一个边栏,这个边栏展现了很多重要信息,包括用户名,用户操作,版规,日历等等等等。

2.但是当用户往下滚,继续往下滚,不断的往下滚~看,我的个人信息看不到了,论坛的帖子是五十条,这也太长了吧,哭。

3.上面那张图还好,至少还可以看见边栏的一个尾巴,继续,会发现如上图,纳尼?右边那片白白的是什么东西,还有,我的个人信息去哪里去看,我的消息提醒点那里去读?

 

由于工作性质比较自由,基于用户的反馈,我深刻意识到这个问题的严重,于是就打算拿起jqeury的武器来帮助广大人民群众解决这个问题,思路嘛,很简单,就是让右边的边栏追随页面的滚动向下。

我第一个想到的是position:fixed这个属性,虽然ie6不支持,但是我觉得潇洒的把ie6抛弃掉,让一部分人先富裕起来。

第一步:我们不需要从一开始就让边栏变成fixed,其实论坛的顶部还有一个挺高的头部,我首先要做的事让鼠标滚过上面的高度以后,边栏的css属性变化,于是如下(由于discuz与jquery冲突,so 木有用$)

var nowtop;
jQuery(window).scroll(function(){
    nowtop = jQuery(document).scrollTop();
    if(nowtop >=200){
        jQuery('.index_right').css({
            'position':'fixed',
            'top':10,
            'right':10
        })
    }
})

说明:页面每次滚动的时候都要去计算一个nowtop值,当nowtop大于等于200像素的时候,index_right就是我们那可爱的右边栏,我需要他变成fixed,并且给定一个top和一个right值。

问题:测试一下,这个问题太多了,第一个问题,如果我鼠标再滚回去,边栏还是fixed在那,第二,我们的论坛宽度是可以切换的,窄屏和宽屏,这个区分是通过html上面的一个class来确定的,这样的话,right值的定位就是一个很大的问题。所以,第一步的改进如下:

var nowtop;
var sideright;
var clientwidth = parseInt(document.body.clientWidth);

jQuery(window).scroll(function(){
    if(jQuery('html').hasClass('widthauto')){
      sideright = (clientwidth*0.05)/2;
    }else{
      sideright = (clientwidth-990)/2;
    }
    nowtop = jQuery(document).scrollTop();
    if(nowtop >=200){
        jQuery('.index_right').css({
            'position':'fixed',
            'top':10,
            'right':sideright
        })
    }else{
        jQuery('.index_right').css({
          'position':'static'
      })
    }
})

说明:增加两个变量,一个放fixed元素的right值,一个计算出屏幕的宽度,right值通过判断html标签是否有widthauto来赋值,这个规则就是我们论坛的规则,宽屏下中间95%,除去两边;窄屏是990的宽,屏幕-990除两边;然后在高度上还需要加个else,来让position由fixed弹回到static,position默认的就是static。

 

第二步:好了,现在终于可以实现,向下滚200像素,右边栏跟随鼠标移动了,而且当我回到顶部的时候,边栏还原到原来的状态。但是现在我突然发现一个严峻的问题,那就是我一直滚呀滚,滚到页面的最底下,边栏依旧是fixed据上边10像素,永远这样。不对啊,这样屏幕过矮看不到全部边栏了,而且底部会覆盖住footer的内容,这也太丑了吧。好吧,看来高度是必须要考虑的问题了。

解决思路,整个页面必须分成三个部分了,向下滚200像素,滚过200像素以及到底下不能让他再滚的时候,那么,什么时候是不能再滚的时候呢,就是屏幕的高度 减去边栏的高度,再减去我滚过的高度,当然底部还有一个footer的高度,不能让最底下边栏紧紧的卡在底部。想起来好复杂,我甚至花了一个示意图才完全高懂这几个高度之间的关系,话不多说,看代码:

var nowtop;
var sideright;
var clientwidth = parseInt(document.body.clientWidth);
var clientheight = parseInt(document.body.clientHeight);
var sideheight = parseInt(jQuery('.index_right').height());

jQuery(window).scroll(function(){
    if(jQuery('html').hasClass('widthauto')){
      sideright = (clientwidth*0.05)/2;
    }else{
      sideright = (clientwidth-990)/2;
    }
    nowtop = jQuery(document).scrollTop();
    if(nowtop >=200 && nowtop <= (clientheight - sideheight - 400)){
        jQuery('.index_right').css({
             'position':'fixed',
             'top':10,
             'right':sideright
        })
    }else if(nowtop >= (clientheight - sideheight - 400)){
        var topv = (clientheight - sideheight - 400) - nowtop;
        jQuery('.index_right').css({
              'position':'fixed',
              'top':topv,
              'right':sideright
        })
    }else{
        jQuery('.index_right').css({
               'position':'static'
        })
    }
})

说明:先算出屏幕高度和边栏的高度,第一阶段,就是毫无顾忌的让边栏追随的阶段 是 nowtop >=200 && nowtop <= (clientheight - sideheight - 400) 这个时候,一旦到了 nowtop >= (clientheight - sideheight - 400) 这个时候,我们的top给他改成负值,让他往上走,这样是最快速解决上面问题的办法。那么,这个负值 我们设为topv,怎么算,屏幕高度减去边栏在减去footer的400,这个值跟目前滚动的差值就是我们需要让边栏向上的值。并且,这个值需要在每次滚动的时候重新计算,所以放在了动作里面,跟上面计算sideright和nowtop一样。

 

第三步:完善优化:我听有人问,前端工程师为什么特别喜欢重复造车轮?我想说的是,前端遇到的情况非常复杂,如果都考虑到,那么这个车轮本身也够大的了。完成上面的那个代码以后,我又发现了几个问题,首先,如果这个页面没那么高,我犯不着去执行这么代码,第二个fixed属性ie6无效,我要给它排除掉,第三个,如果屏幕的尺寸或者浏览器尺寸小于990,那么right的计算会出现错误,第四个,如果浏览器resize,所有的东西还是原来的样子,会乱掉。基于上述这些问题,我做了下面这些完善,话不多说,代码上,这也是我的最终版:

var nowtop;
var clientwidth = parseInt(document.body.clientWidth);
var sideright;
var clientheight = parseInt(document.body.clientHeight);
var sideheight = parseInt(jQuery('.index_right').height());

if(!(jQuery.browser.msie && jQuery.browser.version == 6.0) && clientheight >= sideheight+400 && clientwidth >=990){
    
    var follow = function(){
    if(jQuery('html').hasClass('widthauto')){
        sideright = (clientwidth*0.05)/2;
    }else{
        sideright = (clientwidth-990)/2;
    }

    nowtop = jQuery(document).scrollTop();
    if(nowtop >=200 && nowtop <= (clientheight - sideheight - 400)){
        jQuery('.index_right').css({
            'position':'fixed',
            'top':10,
            'right':sideright
        })
    }else if(nowtop >= (clientheight - sideheight - 400)){
        var topv = (clientheight - sideheight - 400) - nowtop;
        jQuery('.index_right').css({
            'position':'fixed',
            'top':topv,
            'right':sideright
        })
    }else{
        jQuery('.index_right').css({
            'position':'static'
        })
    }
    };
    jQuery(window).resize(function(){
        clientwidth = parseInt(document.body.clientWidth);
        if(clientwidth>=990){
            follow();
        }
    })
    .scroll(follow);

}

说明:首先,所有的东西都保证在 非ie6,屏幕高度要大于边栏高度+400,屏幕宽度大于990的情况下执行。然后,我把所有的动作代码起了个名字叫做follow,这样的好处是jQuery(window)可以写一个很酷的方法串,.resize 后面直接接 .scroll。 resize的时候,我们重新计算的屏幕的宽度,如果宽度合格执行follow,滚动时候也执行follow。

 

结语:当我把这个自认为很酷的功能做出来,并自作主张的放到线上以后,人们发现了一个新的问题,那就是我要滚到边栏的最底部有些困难,尤其是在很高的页面,我一定要滚到页面的最底部才能看到边栏底部的内容,虽然我极力坚持保留这个功能,但是由于边栏底部将来会放置广告,所以我只好忍痛割爱了。

posted on 2012-12-27 18:14  fishenal  阅读(419)  评论(0)    收藏  举报