不使用jQuery的自由滚动粘性侧边栏

15

我正在尝试实现这个Stack Overflow问题中概述的内容,但不使用jQuery依赖:stackoverflow.com/questions/18358816/sticky-sidebar-stick-to-bottom-when-scrolling-down-top-when-scrolling-up

但我不想劫持那个问题。

基本上,我希望侧边栏中的内容在滚动时独立滚动,但当视口到达侧边栏内容的任一端时固定。

我的主要难点似乎是当侧边栏绝对定位并位于容器的顶部和底部之间时,无法计算elementTop变量。

以下是完整代码:

var StickySidebar = function(eventie) {

var container, containerTop, containerHeight,  // container
element, elementTop, elementHeight, elStyle,  // element
viewportTop = -1, viewportHeight, documentTop, // viewport
lastViewportTop, scrollingDown, top = false , bottom = false,// sticky vars

scroll = window.requestAnimationFrame ||
         window.webkitRequestAnimationFrame ||
         window.mozRequestAnimationFrame ||
         window.msRequestAnimationFrame ||
         window.oRequestAnimationFrame ||
         function(callback){ window.setTimeout(callback, 1000/60); },

options =  {
    container : document.querySelector('.sidebar-container'),
    element : document.querySelector('.sidebar'),
    sidebarClass : 'sidebar',
    bottomOffset : -15,
    topOffset: 90,
},

_updateValue = function() {
    viewportHeight = window.innerHeight;
},

_offset = function(obj) {    
    var ol = ot = 0;
    if (obj.offsetParent) {
        do {
            ol += obj.offsetLeft;
            ot += obj.offsetTop;
        } while (obj = obj.offsetParent);
    }
    return {
        left: ol,
        top: ot
    };
},


init = function(){
    if(options.element !== null) {

        container = options.container;
        containerTop = offset(container).top;
        containerHeight = container.clientHeight;

        element = options.element;
        elementTop = offset(element).top;
        elementHeight = options.element.clientHeight;

        lastViewportTop = window.scrollY;
        viewportHeight = window.innerHeight;

        eventie.bind(document, "scroll", _loop);
        eventie.bind(window, "resize", _updateValue);

    }
},

_loop = function() {
    if (viewportTop == window.pageYOffset) {
        scroll(_loop);
        return false;
    } else viewportTop = window.pageYOffset;

    _updateValue();

    var viewportBottom, elementTooBig, topOffset;

    elementTop = offset(element).top;

    elementHeight = element.clientHeight;
    containerHeight = container.clientHeight;
    scrollingDown = viewportTop > lastViewportTop;
    elementTooBig = elementHeight > viewportHeight;

    console.log("elementTop : " + elementTop);
    console.log("viewportTop : " + viewportTop);

    if (scrollingDown) {

        if (viewportTop + viewportHeight >= elementTop + elementHeight) {
            element.setAttribute('style','position:fixed; bottom:30px;');
        } else {
            element.setAttribute('style','position:absolute; top:'+ elementTop +'px;'); // issue 1
    }

    if (viewportTop + viewportHeight > containerTop + containerHeight) {
        element.setAttribute('style','position:absolute; bottom:0;');
    }

} else {

    if (viewportTop < containerTop - 60) {
        element.removeAttribute('style');
        return;
    }

    if (viewportTop <= elementTop) {
        element.setAttribute('style','position:fixed; top:90px;');
    } else {
        element.setAttribute('style','position:absolute; top:'+ elementTop +'px;');
        elementTop = viewportTop + elementTop;
    }

}

lastViewportTop = viewportTop;

};


return {
    init: init
};

}(eventie);

我已经试图解决这个问题几周了,它让我感到疯狂。非常感谢任何帮助。


你可以使用 position: fixed; 的 CSS 属性来解决这个问题。而且你可以在小屏幕上使用 响应式设计。因此不需要使用 JS。 - nloomans
谢谢回复,但那不行。不是要冒犯您,但我认为您没有完全理解问题。 - Seán O'Grady
1
你要将这个答案翻译成纯JS吗? - approxiblue
我已经尝试过了,但他正在使用CSS变换而不是切换固定定位。虽然它可以工作,但性能并不理想。 - Seán O'Grady
1个回答

5
如果你只是想实现所需的结果而不一定要自己创建 - 那么有许多JavaScript库可以提供此功能。例如,Stickyfill 实际上是一个用于填充 position: sticky 的 polyfill,该特性 仅在 Firefox 41+ 和 Safari 8+ 中原生支持。这里是 演示,包含各种您可以想象的粘性效果 :)。P.S. 乍一看,您可能会注意到jQuery的某些内容,但它是纯JavaScript,并且只是添加了一个jQuery扩展。

2
这个 polyfill 似乎不支持固定在底部。 - approxiblue
@approxiblue 不,实际上它确实允许您将元素固定在底部。 - Alexander Mikhalchenko
哪个示例?在README中说它不行。 - approxiblue
@approxiblue 嗯,这很奇怪,我刚刚克隆了仓库并检查了“demos/demo.html”。顺便说一下,问题已经更新了。 - Alexander Mikhalchenko
@approxiblue 非常抱歉,我检查了错误的代码库。 - Alexander Mikhalchenko
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接