master
This commit is contained in:
parent
f46a01daf2
commit
57811df6e2
|
|
@ -0,0 +1,22 @@
|
|||
.block {
|
||||
height: 300px;
|
||||
border: 3px solid #ccc;
|
||||
margin-bottom: 20px;
|
||||
color: white;
|
||||
padding: 24px;
|
||||
line-height: 32px;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.lazyloadImg{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
&>li{
|
||||
width: 400px;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
img{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import React, { useEffect, useRef } from "react";
|
||||
import styles from "../../index.less";
|
||||
|
||||
interface OwnProps {}
|
||||
|
||||
type Props = OwnProps;
|
||||
|
||||
const Index: React.FC<Props> = (props) => {
|
||||
const itemRef = useRef<HTMLElement[]>([]);
|
||||
const ob = new IntersectionObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting) {
|
||||
const img: any = entry.target;
|
||||
img.src = img.dataset.src;
|
||||
ob.unobserve(entry.target);
|
||||
}
|
||||
}
|
||||
});
|
||||
useEffect(() => {
|
||||
if (itemRef.current) {
|
||||
_.forEach(itemRef.current, (item) => {
|
||||
ob.observe(item);
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (itemRef.current) {
|
||||
_.forEach(itemRef.current, (item) => {
|
||||
ob.unobserve(item);
|
||||
});
|
||||
}
|
||||
};
|
||||
}, [itemRef.current]);
|
||||
return (
|
||||
<ul className={styles.lazyloadImg}>
|
||||
{_.map(
|
||||
Array.from({ length: 200 }, () => Math.floor(Math.random() * 100)),
|
||||
(item, index) => (
|
||||
<li key={index}>
|
||||
<img data-src={`https://picsum.photos/300/300?random=${index}`} alt="" src={require("../default.jpeg")} ref={(el) => (itemRef.current[index] = el as HTMLElement)} />
|
||||
</li>
|
||||
)
|
||||
)}
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
export default Index;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.0 KiB |
|
|
@ -0,0 +1,43 @@
|
|||
import React from "react";
|
||||
import SlideInItem from "./slideInItem";
|
||||
|
||||
interface OwnProps {}
|
||||
|
||||
type Props = OwnProps;
|
||||
|
||||
const list = [
|
||||
{ id: 1, bg: "red" },
|
||||
{ id: 2, bg: "blue" },
|
||||
{ id: 3, bg: "green" },
|
||||
{ id: 4, bg: "yellowgreen" },
|
||||
{ id: 5, bg: "orange" },
|
||||
{ id: 6, bg: "pink" },
|
||||
{ id: 7, bg: "antiquewhite" },
|
||||
{ id: 8, bg: "darkseagreen" },
|
||||
{ id: 9, bg: "purple" },
|
||||
{ id: 10, bg: "red" },
|
||||
{ id: 11, bg: "black" }
|
||||
];
|
||||
const Index: React.FC<Props> = (props) => {
|
||||
const map = new WeakMap();
|
||||
const ob = new IntersectionObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting) {
|
||||
const animation = map.get(entry.target);
|
||||
if (animation) {
|
||||
animation.play();
|
||||
ob.unobserve(entry.target);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return (
|
||||
<>
|
||||
{list.map((item, index) => {
|
||||
return <SlideInItem key={index} item={item} ob={ob} map={map}></SlideInItem>;
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Index;
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
import React, { useEffect, useRef } from "react";
|
||||
import styles from "../index.less";
|
||||
|
||||
interface OwnProps {
|
||||
item: any;
|
||||
ob: any;
|
||||
map: any;
|
||||
}
|
||||
|
||||
type Props = OwnProps;
|
||||
const SLIDE_FADE_DISTANCE = 50;
|
||||
const SLIDE_FADE_DURATION = 1000;
|
||||
|
||||
const isBelowViewport = (el: HTMLDivElement) => {
|
||||
const rect = el.getBoundingClientRect();
|
||||
return rect.top - SLIDE_FADE_DISTANCE > window.innerHeight;
|
||||
};
|
||||
const slideInItem: React.FC<Props> = (props) => {
|
||||
const { item, ob, map } = props;
|
||||
const itemRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (itemRef.current && ob) {
|
||||
if (!isBelowViewport(itemRef.current)) {
|
||||
return;
|
||||
}
|
||||
const animation = itemRef.current.animate(
|
||||
[
|
||||
{
|
||||
transform: `translateY(${SLIDE_FADE_DISTANCE}px)`,
|
||||
opacity: 0.1
|
||||
},
|
||||
{
|
||||
transform: `translateY(0)`,
|
||||
opacity: 1
|
||||
}
|
||||
],
|
||||
{
|
||||
duration: SLIDE_FADE_DURATION,
|
||||
easing: "ease-in-out",
|
||||
fill: "forwards" // 当动画完成后,保留最后一个关键帧的样式
|
||||
}
|
||||
);
|
||||
animation.pause();
|
||||
map.set(itemRef.current, animation);
|
||||
ob.observe(itemRef.current);
|
||||
}
|
||||
|
||||
return () => {
|
||||
ob.unobserve(itemRef.current);
|
||||
};
|
||||
}, [itemRef.current]);
|
||||
|
||||
return (
|
||||
<div className={styles.block} ref={itemRef} style={{ backgroundColor: item.bg }}>
|
||||
<h3>The most popular component library</h3>
|
||||
|
||||
<h5>for Tailwind CSS</h5>
|
||||
<p>daisyUI adds component class names to Tailwind CSS so you can make beautiful websites faster than ever.</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default slideInItem;
|
||||
Loading…
Reference in New Issue