Kavşak Gözlemcisi | Web uygulamanızda sonsuz kaydırma oluşturma

Nov 25 2022
Mağara insanı değilseniz veya Jeff Bezos'tan nefret etmiyorsanız (nefret etseniz bile farketmez) internetten alışveriş yapmış olmalısınız. Bu çevrimiçi mağazalarda bir ürün aradığınızda, size bir sonuç listesi sunulur.
Unsplash'ta SpaceX'in fotoğrafı

Mağara insanı değilseniz veya Jeff Bezos'tan nefret etmiyorsanız (nefret etseniz bile farketmez) internetten alışveriş yapmış olmalısınız. Bu çevrimiçi mağazalarda bir ürün aradığınızda, size bir sonuç listesi sunulur. Benim gibi tuhaf biri değilseniz ve çok spesifik olan "insan kanına batırılmış kaplan dişi " aramıyorsanız , arama sorgunuzun binlerce ürün bulma şansı vardır. Tarayıcınızın tüm bu 1000'den fazla öğeyi bir arada yüklediğini düşünüyor musunuz? Hayır , bu, tarayıcının kullanıcı arayüzünü işlemesi ve hesaplaması için çok fazla veri olurdu. Yine de, sonucunuzun sonuna ulaşmaya devam ettikçe öğe almaya devam edersiniz. Buna sonsuz kaydırma denir .

İşte YouTube ana sayfasında sonsuz kaydırma örneği.

Sonsuz kaydırmayı açıklayan gif

Bunu JavaScript kullanarak başarmak için birkaç teknik vardır, ancak en verimli olanı IntersectionObserver adlı tatlı bir web api kullanmaktır. Kendi mini, sonsuz kaydırılabilir listemizi uygulamak için bu API'yi nasıl kullanacağımızı görelim.

Konsept, görüntü alanına her geldiğinde bir html öğesini gözlemlemek ve ardından bir geri aramayı tetiklemektir. İşte bu gözlemciyi nasıl oluşturacağınız.

Buna benzeyen bir html dosyası oluşturalım.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Infinte Scroll</title>
</head>
<style>
    .product {
        padding: 20px;
        border: 1px solid black;
        margin-bottom: 20px;
        opacity: 0;
        margin-left: 100px;
        transition: all 300ms;
    }
    .visible {
        opacity: 1;
        margin-left: 0px;
    }
</style>
<body>
    <div id="container">
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
    </div>

    <script src="./index.js"></script>
</body>
</html>

İlk önce tüm ürün kartlarını sınıf adlarına göre alalım

const cards = document.querySelectorAll('.product');

const productCards= document.querySelectorAll('.product');

const observer = new IntersectionObserver((entries) => {
    // Todo
}, {
    threshold: 0.95,
});

productCards.forEach((card) => {
  observer.observe(card);
})

Yapıcıdaki başka bir parametre bir nesnedir. Bu nesne, bu belirli gözlemci için seçenekleri ifade eder. Bu durumda, sadece eşiğimiz var. buradaki eşik , 0'dan 1'e kadar herhangi bir değer alabilen bir sayıdır . Bu, gözlemlediğimiz öğenin, kesişen kabul edilmesi için görünüm alanında görünür olması gereken yüzdesini belirtir . 0.95 değerini verdik, yani herhangi bir ürün kartının %95'i vitrine geldiğinde, o kart vitrinle kesişiyor kabul edilecek.

Şimdi index.html dosyamıza geri dönelim . Ayrıca , styled etiketinde tanımlanan görünür başka bir stil sınıfımız var. Bu stil, ürün kartımıza uygulandığında, küçük bir animasyonla ( geçiş özelliği) kartı tekrar görünür hale getirecektir.

Gözlemcimizde, görünüm alanında en az %95 oranında bulunan tüm ürün kartları görünecek ve geri kalanı gizlenecek şekilde değişiklikler yapalım.

const productCards = document.querySelectorAll('.product');

const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        entry.target.classList.toggle('visible', entry.isIntersecting);
    })
}, {
    threshold: 0.95
});

productCards.forEach((card) => {
    observer.observe(card);
});

Yine de bir sorun var. Yukarı kaydırdığımızda, öğe kesiştiğinde görünür sınıfı değiştirecek bir mantığımız olduğu için , kesişmediğinde bu sınıfı da kaldırır. Yani yukarı kaydırdığımızda kartlarımızın üstten kaybolduğunu görüyoruz. Bunu düzeltmek için, zaten kesişmiş olan kartları gözlemlemeyi bırakacağız.

const productCards = document.querySelectorAll('.product');

const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        entry.target.classList.toggle('visible', entry.isIntersecting);
        // unobserving entries which have already intersected
        if (entry.isIntersecting) observer.unobserve(entry.target);
    })
}, {
    threshold: 0.95
});

productCards.forEach((card) => {
    observer.observe(card);
});

İlk olarak, sadece son kartı gözlemleyecek başka bir gözlemci oluşturacağız.

const lastCardObserver = new IntersectionObserver((entries) => {
    const lastCard = entries[0];
    if (!lastCard.isIntersecting) return;
    loadMoreCards();
    lastCardObserver.unobserve(lastCard.target);
    lastCardObserver.observe(document.querySelector('.product:last-child'));
}, {
    threshold: 0.95
});

lastCardObserver.observe(document.querySelector('.product:last-child'));

function loadMoreCards() {
    const container = document.getElementById('container');
    for (let i = 0; i < 10; i++) {
        const element = document.createElement('div');
        element.classList.add('product');
        element.innerText = 'Product';
        observer.observe(element);
        container.appendChild(element);
    }
}

Şimdi böyle görünüyor!

Mükemmel Sonsuz Kaydırma!

Artık gerçek dünya uygulamalarında daha fazla kart yüklemek yerine API kullanarak yeni veriler getireceğiz.

Bu API'yi uygulamalarınızda yaratıcı bir şekilde nasıl kullanabileceğinizi bana bildirin .