SOURCE

console 命令行工具 X clear

                    
>
console
document.addEventListener('DOMContentLoaded', function () {
    const sidebar = document.querySelector('#sidebar');
    const first = document.querySelector('#first');
    const last = document.querySelector('#last');
    initFixedSidebar(sidebar,first,last)
});

function initFixedSidebar (sideBar,first,last){
    let isOverTop, isOverBottom;
    const FIXED_VALUE_TOP = 8;
    const FIXED_VALUE_BOTTOM = 8;
    const domObserver = new IntersectionObserver((entries, observer) => {
        entries.forEach(entry => {
            if (entry.target == first) {
                isOverTop = entry.isIntersecting
                if (entry.isIntersecting) {
                    isOverBottom = false
                }
            }
            if (entry.target == last) {
                isOverBottom = entry.isIntersecting
                if (entry.isIntersecting) {
                    isOverTop = false
                }
            }
        });
        //threshold:0表示初进入视口时触发 1表示完全进入视口时触发
    }, { root: null, rootMargin: '0px', threshold: [1] }); 
    domObserver.observe(first);
    domObserver.observe(last);
    setTimeout(() => {
        // 交叠监听器 在页面渲染时会监听到,而那时的数据不是我们想要的初始数据;
        // 在这进行初始化;
        // 需要延迟执行
        isOverBottom = false
        isOverTop = true
    }, 100);
    let lastScrollTop = window.pageYOffset || document.documentElement.scrollTop;
    window.addEventListener('scroll', () => {
        const currentScrollPosition = window.pageYOffset;
        const scrollDistance = currentScrollPosition - lastScrollTop;
        if (currentScrollPosition >= lastScrollTop) {
            if (isOverBottom) {
                sidebar.style.position = 'fixed';
                sidebar.style.bottom = FIXED_VALUE_BOTTOM+'px';
                sidebar.style.top = '';
            } else {
                const bottom = window.getComputedStyle(sidebar).getPropertyValue('bottom');
                sidebar.style.position = 'fixed';
                sidebar.style.top = '';
                sidebar.style.bottom = `calc( ${scrollDistance}px + ${bottom || 0} )`;
            }
        } else if (currentScrollPosition <= lastScrollTop) {
            if (isOverTop) {
                sidebar.style.position = 'fixed';
                sidebar.style.top = FIXED_VALUE_TOP+'px';
                sidebar.style.bottom = '';
            } else {
                const bottom = window.getComputedStyle(sidebar).getPropertyValue('bottom');
                sidebar.style.position = 'fixed';
                sidebar.style.bottom = `calc( ${bottom} + ${scrollDistance}px )`;
                sidebar.style.top = '';
            }
        }
        lastScrollTop = currentScrollPosition;
    });
}
<div id='body'>
	<div id='content'>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
	</div>
    <div class="sidebar-perch"></div>
	<div id='sidebar'>
		<div class="section" id="first"></div>
		<div class="section"></div>
		<div class="section"></div>
		<div class="section"></div>
		<div class="section" id="last"></div>
	</div>
</div>
#body {
    display: flex;
    justify-content: center;
    align-items: flex-start;
    position: relative;
}

#content {
    width: 50%;
    background-color: white;
}

#sidebar {
    position: fixed;
    right: 10%;
    width: 25%;
    height: auto;
    background-color: white;
}
.sidebar-perch{
    width: 25%;
}

.item {
    width: 80%;
    height: 320px;
    margin: 20px;
    background-color: darkmagenta;
}

.section {
    width: 80%;
    height: 280px;
    margin: 20px;
    background-color: sienna;
}