当元素可见时(滚动之前)交叉观察器触发

lha*_*rby 5 javascript intersection-observer webapi

我正在尝试使用 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));
Run Code Online (Sandbox Code Playgroud)

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

if(entry.isIntersecting && isCartItemClicked)

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

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

我在这里制作了一个JSFIDDLE(其中有 HTML 和 CSS 标记)。

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

在此输入图像描述

Gen*_*ser 1

这有点棘手,但可以通过创建一个someObserverEntriesVisibleobserverCallback. 有了这个,我们就可以定义如何将按钮触发器与每个相交条目的观察者回调分开处理。

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));
Run Code Online (Sandbox Code Playgroud)
#content {
  height: 500px;
}

.active {
  background-color: orange;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)