元素可见时(滚动前)Intersection Observer 触发

Intersection Observer trigger when element is visible (before scrolling)

我正在尝试使用 Intersection Observer API。我有一个在我的第一次迭代中工作的函数。基本逻辑是,如果用户向下滚动并从篮子中添加或删除项目,一旦篮子再次出现(因为它位于文档顶部),我就会触发 API 调用。

问题是它不会在滚动前触发该功能,我想在项目可见或滚动后再次可见时触发它(第二部分正在运行)

这是原始js:

var observerTargets = document.querySelectorAll('[id^="mini-trolley"]');
var observerOptions = {
    root: null, // null means root is viewport
    rootMargin: '0px',
    threshold: 0.01 // trigger callback when 1% of the element is visible
}
var activeClass = 'active';
var trigger = $('button');
var isCartItemClicked = false;

trigger.on('click', function() {
    isCartItemClicked = true;
});

function observerCallback(entries, observer) { 
    entries.forEach(entry => {
        if(entry.isIntersecting && isCartItemClicked){
            $(observerTargets).removeClass(activeClass);
            $(entry.target).addClass(activeClass);
            isCartItemClicked = false;
            console.log('isCartItemClicked and in view');
            // do my api call function here
        } else {
            $(entry.target).removeClass(activeClass);
        }
    });
}

var observer = new IntersectionObserver(observerCallback, observerOptions);
[...observerTargets].forEach(target => observer.observe(target));

我已经更新了它,现在它会检查该项目是否可见。所以我更新了:

if(entry.isIntersecting && isCartItemClicked)

if((entry.isVisible || entry.isIntersecting) && isCartItemClicked)

据我了解,问题是观察者仅在滚动时触发,但 entry.isVisible 是观察者回调函数的一部分。

我做了一个 JSFIDDLE here(有 HTML 和 CSS 标记)。

是否可以修改代码。奇怪的是 MDN page 没有提到 isVisible 属性,但它显然是函数的一部分。

这个有点棘手,但可以通过创建由 observerCallback 设置的 someObserverEntriesVisible 参数来完成。有了它,我们就可以定义按钮触发器应该如何与每个相交条目的观察者回调分开处理。

const observerTargets = document.querySelectorAll('[id^="mini-trolley"]');
const observerOptions = {
    root: null, // null means root is viewport
    rootMargin: '0px',
    threshold: 0.01 // trigger callback when 1% of the element is visible
};
const activeClass = 'active';
const trigger = $('button');

let isCartItemClicked = false;
let someObserverEntriesVisible = null;
let observerEntries = [];

trigger.on('click', () => {
    isCartItemClicked = true;
    if (someObserverEntriesVisible) {
        console.log('fired from button');
        observerCallback(observerEntries, observer, false);
    }
});

function observerCallback(entries, observer, resetCartItemClicked = true) {
    observerEntries = entries;
    someObserverEntriesVisible = false;
    entries.forEach(entry => {
        someObserverEntriesVisible ||= entry.isIntersecting;
        if (entry.isIntersecting && isCartItemClicked) {
            $(entry.target).addClass(activeClass);
            // add API call here
            if (resetCartItemClicked) {
                isCartItemClicked = false;
                console.log('fired from observer');
            }
        } else {
            $(entry.target).removeClass(activeClass);
        }
    });
}

const observer = new IntersectionObserver(observerCallback, observerOptions);
[...observerTargets].forEach(target => observer.observe(target));
#content {
  height: 500px;
}

.active {
  background-color: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="mini-trolley">Observer target1</div>
<button>Top button</button>
<div id="content"></div>
<div id="mini-trolley">Observer target2</div>
<button>Bottom button</button>