使用getBoundingClientRect方法实现简洁的sticky组件的(3)

<div> <ul data-target="#main-container"> <li role="presentation"><a href="#">Home</a></li> <li role="presentation"><a href="#">Profile</a></li> <li role="presentation"><a href="#">Messages</a></li> </ul> </div> <div> <div> ... </div> ... </div>

固定在底部的html结构:

<div> <div> ... </div> ... </div> <div> <ul data-target="#main-container"> <li role="presentation"><a href="#">Home</a></li> <li role="presentation"><a href="#">Profile</a></li> <li role="presentation"><a href="#">Messages</a></li> </ul> </div>

以上#main-container就是我们的target元素,#sticky就是我们的sticky元素,还需要注意两点:

a. 顺序问题,两种结构中,target元素与sticky的父元素顺序位置是反的;

b. sticky元素外面必须包裹一层元素,而且还得给这一层元素设置height属性:

.sticky-wrapper { margin-bottom: 10px; height: 52px; }

这是因为当sticky元素被固定的时候,它会脱离普通文档流,所以要利用它的父元素把sticky元素的高度在普通文档流中撑起来,以免在固定效果出现的时候,target元素的内容出现跳动的情况。

2)固定效果

让一个元素固定在浏览器的某个位置,当然是通过position: fixed来弄,所以可以用两个css类来实现固定在顶部和固定在底部的效果:

.sticky--in-top,.sticky--in-bottom { position: fixed; z-index: 1000; } .sticky--in-top { top: 0; } .sticky--in-bottom { bottom: 0; }

当我们判断元素需要被固定在顶部的时候,就给它添加.sticky--in-top的css类;当我们判断元素需要被固定在底部的时候,就给它添加.sticky--in-bottom的css类。

3)滚动回调

控制sticy元素固定的逻辑显然要写在window的scroll事件回调中(有了前面对实现思路以及判断条件的说明,相信理解下面这段代码应该会很容易):

固定在顶部的回调逻辑:

$(window).scroll(function() { var rect = $target[0].getBoundingClientRect(); if (rect.top < 0 && (rect.bottom - stickyHeight) > 0) { !$elem.hasClass('sticky--in-top') && $elem.addClass('sticky--in-top').css('width', stickyWidth + 'px'); } else { $elem.hasClass('sticky--in-top') && $elem.removeClass('sticky--in-top').css('width', 'auto'); } });

其中:$target是target元素的jq对象,$elem是sticky元素的jq对象,stickyHeight是sticky元素的高度,stickyWidth是sticky元素的宽度。由于sticky元素固定时,脱离原来的文档流,需要设置宽度才能显示跟固定前一样的宽度。

固定在底部的回调逻辑:

$(window).scroll(function() { var rect = $target[0].getBoundingClientRect(), docClientWidth = document.documentElement.clientHeight; if (rect.bottom > docClientWidth && (rect.top + stickyHeight) < docClientWidth) { !$elem.hasClass('sticky--in-bottom') && $elem.addClass('sticky--in-bottom').css('width', stickyWidth + 'px'); } else { $elem.hasClass('sticky--in-bottom') && $elem.removeClass('sticky--in-bottom').css('width', 'auto'); } });

这里是为了把回调逻辑说的更清楚才把代码分成两份,最后给的实现会把这两个代码合并成一份:)

4)函数节流

函数节流通常应用于window的scroll事件,resize事件以及普通元素的mousemove事件,因为这些事件由于鼠标或滚轮操作很频繁,会导致回调连续触发,如果回调里面含有DOM操作,这种连续调用就会影响页面的性能,所以很有必要控制这类回调的执行次数,函数节流就是做这个的,我这里提供了一个很简单的函数节流实现:

function throttle(func, wait) { var timer = null; return function() { var self = this, args = arguments; if (timer) clearTimeout(timer); timer = setTimeout(function() { return typeof func === 'function' && func.apply(self, args); }, wait); } }

这个函数可以控制func所指定的函数,执行的间隔指定为wait指定的毫秒数,利用它,我们可以把前面的滚动回调改动一下,比如固定在顶部的情况改成:

$(window).scroll(throttle(function() { var rect = $target[0].getBoundingClientRect(), docClientWidth = document.documentElement.clientHeight; if (rect.bottom > docClientWidth && (rect.top + stickyHeight) < docClientWidth) { !$elem.hasClass('sticky--in-bottom') && $elem.addClass('sticky--in-bottom').css('width', stickyWidth + 'px'); } else { $elem.hasClass('sticky--in-bottom') && $elem.removeClass('sticky--in-bottom').css('width', 'auto'); } }, 50);

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgyjwx.html