reactjs 当图像靠近视口的底部或右侧时,在包含多个水平滚动部分的屏幕上延迟加载图像

lymnna71  于 2023-06-05  发布在  React
关注(0)|答案(1)|浏览(110)

目标:我想为我的图像加载,一旦他们在一定的百分比或像素数(碰巧是20%,在我的例子)的权利或底部的视口
我尝试了两种方法。我在代码中对我的方法做了注解,您可以轻松地打开和关闭每种方法。在一种方法中,右边距行为正确,但下边距行为不正确。而另一种方法则相反:右边距不能正常工作,但下边距可以。
JavaScript:

import React, {useEffect} from 'react';
import './test.css';

// dummy test data
const coffeeShops = [
    {
        title: 'Coffee Shop 1',
        photos: [
            'picture 1 of Coffee Shop 1',
            'picture 2 of Coffee Shop 1',
            'picture 3 of Coffee Shop 1',
            'picture 4 of Coffee Shop 1'
        ]
    },
    {
        title: 'Coffee Shop 2',
        photos: [
            'picture 1 of Coffee Shop 2',
            'picture 2 of Coffee Shop 2',
            'picture 3 of Coffee Shop 2',
            'picture 4 of Coffee Shop 2'
        ]
    },
    {
        title: 'Coffee Shop 3',
        photos: [
            'picture 1 of Coffee Shop 3',
            'picture 2 of Coffee Shop 3',
            'picture 3 of Coffee Shop 3',
            'picture 4 of Coffee Shop 3'
        ]
    },
    {
        title: 'Coffee Shop 4',
        photos: [
            'picture 1 of Coffee Shop 4',
            'picture 2 of Coffee Shop 4',
            'picture 3 of Coffee Shop 4',
            'picture 4 of Coffee Shop 4'
        ]
    }
]

export const Test = () => {
    useEffect(() => {
        const svgs = document.querySelectorAll('.mySvg');
        // I am setting the images to load once they come within 20% of the right or bottom of the viewport.
        const rootMargin = '0% 20% 20% 0%';

        // Approach 1:
        // bottom viewport works!
        // right viewport doesn't work: The images load right when they intersect with the right side of the viewport (i.e. 0% instead of the 20% that I set) :(
        createObserver(svgs, rootMargin, null);

        // Approach 2: (the exact opposite happens)
        // bottom viewport doesn't work: If you scroll down you can see that all the images already loaded when the page loaded :(
        // right viewport works!
        // const scrollContainers = document.querySelectorAll('.scroll-container');
        // for (const scrollContainer of scrollContainers) {
        //     createObserver(svgs, rootMargin, scrollContainer);
        // }
    }, [])

    return (
        <>
            <div style={{marginBottom: '50px'}}>Awesome Coffee Shops:</div>

            {coffeeShops.map(shop => {
                return (
                    <>
                        <div className='scroll-container'>
                            {shop.photos.map(photo => {
                                return (
                                    <svg width='4032' height='3024' className='mySvg'>
                                        <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
                                    </svg>

                                );
                            })}
                        </div>
                        <div>{shop.title}</div>
                    </>
                );
            })}
        </>
    );
};

export const createObserver = (svgs, rootMargin, root) => {
    const config = {
        root,
        rootMargin,
        threshold: 0
    };

    const lazyImageObserver = new IntersectionObserver(function (entries, observer) {
        entries.forEach(function (entry) {
            if (entry.isIntersecting) {
                const svg = entry.target;
                setTimeout(() => svg.childNodes[0].setAttribute('fill', 'purple'), 500); // the setTimeout simulates downloading an image
                observer.unobserve(svg);
            }
        });
    }, config);

    svgs.forEach(function (svg) {
        lazyImageObserver.observe(svg);
    });
};

CSS

.scroll-container {
    overflow: auto;
    white-space: nowrap;
}
zazmityj

zazmityj1#

如果你的每一种方法只在一个方面有效,那就两个都用。使用方法1为每个容器附加观察者,使用方法2将每个图像加载到其容器中。

function loadContainer(entries, observer) {
  entries.forEach(function(entry) {
    if (entry.isIntersecting) {
      const container = entry.target;
      const svgs = container.querySelectorAll('.mySvg');
      createObserver(svgs, rootMargin, container, loadImage);
      observer.unobserve(container);

    }
  });
}

function loadImage(entries, observer) {
  entries.forEach(function(entry) {
    if (entry.isIntersecting) {
      const svg = entry.target;
      setTimeout(() => svg.children[0].setAttribute('fill', 'purple'), 500); // the setTimeout simulates downloading an image
      observer.unobserve(svg);
    }
  });
}
const createObserver = (targets, rootMargin, root, callBack) => {
  const config = {
    root,
    rootMargin,
    threshold: 0
  };
  const observer = new IntersectionObserver(callBack, config);
  targets.forEach(function(target) {
    observer.observe(target);
  });
};
const scrollContainers = document.querySelectorAll('.scroll-container');
const rootMargin = '0% 20% 20% 0%';
createObserver(scrollContainers, rootMargin, null, loadContainer);
.scroll-container {
  overflow: auto;
  white-space: nowrap;
}
<div style="margin-bottom: 50px">Awesome Coffee Shops:
  <div class='scroll-container'>
    <svg width='4032' height='3024' class='mySvg'>
      <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
    </svg>
    <svg width='4032' height='3024' class='mySvg'>
      <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
    </svg>
    <svg width='4032' height='3024' class='mySvg'>
      <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
    </svg>
    <svg width='4032' height='3024' class='mySvg'>
      <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
    </svg>
  </div>
  <div>Coffee Shop 1</div>
  <div class='scroll-container'>
    <svg width='4032' height='3024' class='mySvg'>
      <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
    </svg>
    <svg width='4032' height='3024' class='mySvg'>
      <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
    </svg>
    <svg width='4032' height='3024' class='mySvg'>
      <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
    </svg>
    <svg width='4032' height='3024' class='mySvg'>
      <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
    </svg>
  </div>
  <div>Coffee Shop 2</div>
  <div class='scroll-container'>
    <svg width='4032' height='3024' class='mySvg'>
      <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
    </svg>
    <svg width='4032' height='3024' class='mySvg'>
      <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
    </svg>
    <svg width='4032' height='3024' class='mySvg'>
     <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
    </svg>
    <svg width='4032' height='3024' class='mySvg'>
      <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
    </svg>
  </div>
  <div>Coffee Shop 3</div>
  <div class='scroll-container'>
    <svg width='4032' height='3024' class='mySvg'>
      <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
    </svg>
    <svg width='4032' height='3024' class='mySvg'>
      <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
    </svg>
    <svg width='4032' height='3024' class='mySvg'>
      <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
    </svg>
    <svg width='4032' height='3024' class='mySvg'>
      <rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
    </svg>
  </div>
  <div>Coffee Shop 4</div>
</div>

相关问题