自定义图片滚动组件

This commit is contained in:
al 2024-08-07 18:08:33 +08:00
parent d976b642ff
commit f442b82354
4 changed files with 207 additions and 172 deletions

View File

@ -101,20 +101,26 @@ footer{
overflow-y: auto; overflow-y: auto;
scroll-behavior: smooth; scroll-behavior: smooth;
} }
.scrollbarBoxX {
/* IE 10+ */
overflow-y: hidden;
overflow-x: auto;
scroll-behavior: smooth;
}
.scrollbarBox::-webkit-scrollbar { .scrollbarBoxX::-webkit-scrollbar, .scrollbarBox::-webkit-scrollbar {
/* display:none; */ /* display:none; */
width: 6px; width: 6px;
} }
.scrollbarBox::-webkit-scrollbar-thumb { .scrollbarBoxX::-webkit-scrollbar-thumb,.scrollbarBox::-webkit-scrollbar-thumb {
border-radius: 10px; border-radius: 10px;
-webkit-box-shadow: inset 0 0 5px rgba(138, 138, 138, 0.2); -webkit-box-shadow: inset 0 0 5px rgba(138, 138, 138, 0.2);
background: nb-theme(background-basic-color-4); background: nb-theme(background-basic-color-4);
} }
.scrollbarBox::-webkit-scrollbar-track { .scrollbarBoxX::-webkit-scrollbar-track,.scrollbarBox::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 5px rgba(138, 138, 138, 0.2); -webkit-box-shadow: inset 0 0 5px rgba(138, 138, 138, 0.2);
border-radius: 10px; border-radius: 10px;
background: nb-theme(background-basic-color-2); background: nb-theme(background-basic-color-2);

View File

@ -72,10 +72,7 @@ export default function RootLayout({ children }) {
<meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-capable" content="yes" />
{/* <!-- 用来定义顶部状态栏的形式默认是default为白色 black为黑色 black-translucent为灰色半透明会占据屏幕的约20px不同的设备可能会有差异--> */} {/* <!-- 用来定义顶部状态栏的形式默认是default为白色 black为黑色 black-translucent为灰色半透明会占据屏幕的约20px不同的设备可能会有差异--> */}
{/* <!-- 在定义了apple-mobile-web-app-capable的前提下设置状态栏的属性值apple-mobile-web-app-status-bar-style才有效 --> */} {/* <!-- 在定义了apple-mobile-web-app-capable的前提下设置状态栏的属性值apple-mobile-web-app-status-bar-style才有效 --> */}
<meta <meta name="apple-mobile-web-app-status-bar-style" content="#ffffff" />
name="apple-mobile-web-app-status-bar-style"
content="#ffffff"
/>
{/* <!-- apple-touch-startup-image用来配置启动动画 --> */} {/* <!-- apple-touch-startup-image用来配置启动动画 --> */}
{/* <!-- 这里要注意,这里图片的尺寸要和设备的静态图片显示尺寸完全对应,差一个像素都会导致启动动画无法显示 --> */} {/* <!-- 这里要注意,这里图片的尺寸要和设备的静态图片显示尺寸完全对应,差一个像素都会导致启动动画无法显示 --> */}
{/* <!-- 下面列举了iPhone的所有尺寸ps:为了方便大家就全部贴出来了!!) --> */} {/* <!-- 下面列举了iPhone的所有尺寸ps:为了方便大家就全部贴出来了!!) --> */}
@ -191,9 +188,16 @@ export default function RootLayout({ children }) {
</head> </head>
<body className={`${inter.className} h-full`}> <body className={`${inter.className} h-full`}>
<main className={`w-full bg-deepBg h-full`}> <main className={`w-full bg-deepBg h-full`}>
{withAuth(<Provider store={store}>{children}</Provider>)} <div id="maskDomBox"></div>
{withAuth(
<Provider store={store}>
<div>
{children}
{/* <ImagesMask ref={imagesMaskRef} /> */}
</div>
</Provider>
)}
{/* <Provider store={store}>{children}</Provider> */} {/* <Provider store={store}>{children}</Provider> */}
<div id="maskDomBox"></div>
</main> </main>
<footer className="fixed left-0 w-screen bg-black"> <footer className="fixed left-0 w-screen bg-black">
<div> <div>

View File

@ -10,12 +10,32 @@ import React, {
import { Mask, Image } from "antd-mobile"; import { Mask, Image } from "antd-mobile";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faAngleLeft, faAngleRight } from "@fortawesome/free-solid-svg-icons"; import { faAngleLeft, faAngleRight } from "@fortawesome/free-solid-svg-icons";
import { createRoot } from "react-dom/client";
const maskDomBox = window ? document?.getElementById("maskDomBox") : null;
console.log(maskDomBox);
const root = createRoot(maskDomBox);
function ImagesMask({}, ref) { function ImagesMask({}, ref) {
const [currentIndex, setCurrentIndex] = useState(0); const [currentIndex, setCurrentIndex] = useState(0);
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const [images, setImages] = useState([]); const [images, setImages] = useState([]);
const [distance, setDistance] = useState(0);
const scrollRef = useRef(null); const scrollRef = useRef(null);
useEffect(() => {
root.render(
<div>
<ImagesMaskContaint
images={images}
visible={visible}
currentIndex={currentIndex}
ref={scrollRef}
setCurrentIndex={setCurrentIndex}
setVisible={setVisible}
setImages={setImages}
/>
</div>
);
// root.render(<div>xxxx</div>);
}, [visible]);
useEffect(() => { useEffect(() => {
if (scrollRef.current) { if (scrollRef.current) {
setTimeout(() => { setTimeout(() => {
@ -27,91 +47,91 @@ function ImagesMask({}, ref) {
show: (arr, index) => { show: (arr, index) => {
setCurrentIndex(index); setCurrentIndex(index);
setImages(arr); setImages(arr);
setVisible(true); setVisible(old=>{
console.log(arr, index,old)
return !old
});
// Mask.show // Mask.show
// const maskDomBox = document.getElementById("maskDomBox"); // const maskDomBox = document.getElementById("maskDomBox");
}, },
close: () => setVisible(false), close: () => setVisible(false),
})); }));
const getDistance = (e) => {
e.stopPropagation(); return <></>;
const distance = scrollRef.current.scrollLeft;
setDistance(distance);
};
const handleMoveImages = (e,index) => {
e.stopPropagation();
// console.log("distance",distance)
if (
distance > window.innerWidth * currentIndex &&
distance < window.innerWidth + window.innerWidth * currentIndex
) {
setCurrentIndex(Math.ceil(distance/414))
} else if(distance < window.innerWidth * currentIndex) {
setCurrentIndex(Math.ceil(distance/414)-1)
}
};
return (
<Mask
visible={visible}
className="z-[99] h-screen flex justify-center items-center"
>
<div className="relative">
<div className="text-center mb-2">
{currentIndex + 1}/{images.length}
</div>
<div
ref={scrollRef}
id="imagesScrollBox"
className="flex overflow-auto"
>
{images.map((item, index) => {
return (
// <Image
// key={index}
// fit="cover"
// className="mr-3"
// // src={process.env.NEXT_PUBLIC_WEB_ASSETS_URL+"/icons/nodata.png"}
// src={item}
// placeholder=""
// width="100vw"
// // height="90vh"
// />
<img
key={index}
src={item}
// onTouchMove={(e) => handleMoveImages(e, index)}
onTouchMove={getDistance}
onTouchEnd={(e) => handleMoveImages(e,index)}
onClick={() => {
setVisible(false), setImages([]), setCurrentIndex(0);
}}
/>
);
})}
</div>
<div className="flex justify-between items-center w-screen absolute top-1/2 px-4 pointer-events-none">
<div
className="w-9 h-9 flex items-center justify-center bg-[#FFFFFF1A] rounded-full float-left pointer-events-auto"
onClick={() => {
setCurrentIndex((old) => (old > 0 ? old - 1 : old));
}}
>
<FontAwesomeIcon icon={faAngleLeft} size="xl" />
</div>
<div
className="w-9 h-9 flex items-center justify-center bg-[#FFFFFF1A] rounded-full float-left pointer-events-auto"
onClick={() => {
setCurrentIndex((old) =>
old < images.length - 1 ? old + 1 : old
);
}}
>
<FontAwesomeIcon icon={faAngleRight} size="xl" />
</div>
</div>
</div>
</Mask>
);
} }
const ImagesMaskContaint = forwardRef(
({ visible, images, currentIndex,setCurrentIndex,setVisible,setImages }, ref) => {
const [distance, setDistance] = useState(0);
const getDistance = (e) => {
e.stopPropagation();
const distance = ref.current.scrollLeft;
setDistance(distance);
};
const handleMoveImages = (e, index) => {
e.stopPropagation();
// console.log("distance",distance)
if (
distance > window.innerWidth * currentIndex &&
distance < window.innerWidth + window.innerWidth * currentIndex
) {
setCurrentIndex(Math.ceil(distance / 414));
} else if (distance < window.innerWidth * currentIndex) {
setCurrentIndex(Math.ceil(distance / 414) - 1);
}
};
return (
<div>
<Mask
visible={visible}
className="z-[1002] h-screen flex justify-center items-center"
>
<div className="relative">
<div className="text-center mb-2">
{currentIndex + 1}/{images.length}
</div>
<div ref={ref} id="imagesScrollBox" className="flex overflow-auto scrollbarBoxX">
{images.map((item, index) => {
return (
<img
key={index}
src={item}
// onTouchMove={(e) => handleMoveImages(e, index)}
onTouchMove={getDistance}
onTouchEnd={(e) => handleMoveImages(e, index)}
onClick={() => {
setVisible(false), setImages([]), setCurrentIndex(0);
}}
/>
);
})}
</div>
<div className="flex justify-between items-center w-screen absolute top-1/2 px-4 pointer-events-none">
<div
className="w-9 h-9 flex items-center justify-center bg-[#FFFFFF1A] rounded-full float-left pointer-events-auto"
onClick={() => {
setCurrentIndex((old) => (old > 0 ? old - 1 : old));
}}
>
<FontAwesomeIcon icon={faAngleLeft} size="xl" />
</div>
<div
className="w-9 h-9 flex items-center justify-center bg-[#FFFFFF1A] rounded-full float-left pointer-events-auto"
onClick={() => {
setCurrentIndex((old) =>
old < images.length - 1 ? old + 1 : old
);
}}
>
<FontAwesomeIcon icon={faAngleRight} size="xl" />
</div>
</div>
</div>
</Mask>
</div>
);
}
);
export default forwardRef(ImagesMask); export default forwardRef(ImagesMask);

View File

@ -7,8 +7,8 @@ import { faAngleUp, faClose } from "@fortawesome/free-solid-svg-icons";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import baseRequest from "@/utils/baseRequest"; import baseRequest from "@/utils/baseRequest";
import Player from "next-video/player"; import Player from "next-video/player";
// import ImagesMask from "@/components/ImagesMask"; import ImagesMask from "@/components/ImagesMask";
// import Viewer from 'react-viewer';
export default function Photos({ export default function Photos({
isUnlocked, isUnlocked,
mediaVisibleRange, mediaVisibleRange,
@ -23,9 +23,10 @@ export default function Photos({
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const currentIndex = useRef(); const currentIndex = useRef();
const swiper = useRef(null); const swiper = useRef(null);
// const imagesMaskRef = useRef(null); const imagesMaskRef = useRef(null);
const router = useRouter(); const router = useRouter();
const base = baseRequest(); const base = baseRequest();
useEffect(() => { useEffect(() => {
if (media) { if (media) {
let imgArr = media.images.map((item) => ({ let imgArr = media.images.map((item) => ({
@ -74,88 +75,92 @@ export default function Photos({
// }, 400); // }, 400);
// 添加左右切换按钮 // 添加左右切换按钮
const btns = document.createElement("div"); // const btns = document.createElement("div");
btns.className = "imagesBtnsControllers"; // btns.className = "imagesBtnsControllers";
const btnL = document.createElement("div"); // const btnL = document.createElement("div");
btnL.className = "imagesBtnsControllerLeft"; // btnL.className = "imagesBtnsControllerLeft";
btnL.addEventListener("click", () => { // btnL.addEventListener("click", () => {
if (currentIndex.current > 0) { // if (currentIndex.current > 0) {
currentIndex.current = currentIndex.current - 1; // currentIndex.current = currentIndex.current - 1;
handleShowImages(currentIndex.current, photos, btns); // handleShowImages(currentIndex.current, photos, btns,interval);
if (!currentIndex.current) { // if (!currentIndex.current) {
btnL.style.opacity = 0.5; // btnL.style.opacity = 0.5;
btnR.style.opacity = 1; // btnR.style.opacity = 1;
} else { // } else {
btnR.style.opacity = 1; // btnR.style.opacity = 1;
btnL.style.opacity = 1; // btnL.style.opacity = 1;
} // }
} // }
}); // });
const btnR = document.createElement("div"); // const btnR = document.createElement("div");
btnR.className = "imagesBtnsControllerRight"; // btnR.className = "imagesBtnsControllerRight";
btnR.addEventListener("click", () => { // btnR.addEventListener("click", () => {
if (currentIndex.current < currentPhotos.length - 1) { // if (currentIndex.current < currentPhotos.length - 1) {
currentIndex.current = currentIndex.current + 1; // currentIndex.current = currentIndex.current + 1;
handleShowImages(currentIndex.current, photos, btns); // handleShowImages(currentIndex.current, photos, btns,interval);
if (currentIndex.current == currentPhotos.length - 1) { // if (currentIndex.current == currentPhotos.length - 1) {
btnR.style.opacity = 0.5; // btnR.style.opacity = 0.5;
btnL.style.opacity = 1; // btnL.style.opacity = 1;
} else { // } else {
btnR.style.opacity = 1; // btnR.style.opacity = 1;
btnL.style.opacity = 1; // btnL.style.opacity = 1;
} // }
} // }
}); // });
btns.append(btnL, btnR); // btns.append(btnL, btnR);
handleShowImages(index, photos, btns); // handleShowImages(index, photos, btns,interval);
// setVisible(true) // setVisible(true)
// imagesMaskRef.current.show(photos.map((item) => item?.url),index) console.log(imagesMaskRef.current);
imagesMaskRef.current.show(
photos.map((item) => item?.url),
index
);
}; };
const handleShowImages = (index, photos, btns) => { // const handleShowImages = (index, photos, btns) => {
const mediaDom = document.createElement("div"); // const mediaDom = document.createElement("div");
mediaDom.style.width = "100vw"; // mediaDom.style.width = "100vw";
document.body.appendChild(mediaDom); // document.body.appendChild(mediaDom);
mediaDom.className = `${ // mediaDom.className = `${
photos[index]?.type == "hid" ? "mediaDom photos-body" : "mediaDom" // photos[index]?.type == "hid" ? "mediaDom photos-body" : "mediaDom"
}`; // }`;
mediaDom.appendChild(btns); // mediaDom.appendChild(btns);
ImageViewer.clear(); // ImageViewer.clear();
ImageViewer.Multi.show({ // ImageViewer.Multi.show({
images: photos.map((item) => item?.url), // images: photos.map((item) => item?.url),
defaultIndex: index, // defaultIndex: index,
renderFooter: (image, index) => { // renderFooter: (image, index) => {
return renderFooter(photos[index]?.type == "hid", mediaDom); // return renderFooter(photos[index]?.type == "hid", mediaDom);
}, // },
getContainer: mediaDom, // getContainer: mediaDom,
onIndexChange: (index) => { // onIndexChange: (index) => {
currentIndex.current = index; // currentIndex.current = index;
mediaDom.className = `${ // mediaDom.className = `${
photos[index]?.type == "hid" ? "mediaDom photos-body" : "mediaDom" // photos[index]?.type == "hid" ? "mediaDom photos-body" : "mediaDom"
}`; // }`;
const leftBtn = document.getElementsByClassName("imagesBtnsControllerLeft")[0] // const leftBtn = document.getElementsByClassName("imagesBtnsControllerLeft")[0]
const rightBtn = document.getElementsByClassName("imagesBtnsControllerRight")[0] // const rightBtn = document.getElementsByClassName("imagesBtnsControllerRight")[0]
if(leftBtn && rightBtn){ // if(leftBtn && rightBtn){
if(!index){ // if(!index){
leftBtn.style.opacity=0.5 // leftBtn.style.opacity=0.5
rightBtn.style.opacity=1 // rightBtn.style.opacity=1
}else if(index==currentPhotos.length-1){ // }else if(index==currentPhotos.length-1){
leftBtn.style.opacity=1 // leftBtn.style.opacity=1
rightBtn.style.opacity=0.5 // rightBtn.style.opacity=0.5
}else{ // }else{
leftBtn.style.opacity=1 // leftBtn.style.opacity=1
rightBtn.style.opacity=1 // rightBtn.style.opacity=1
} // }
} // }
}, // },
afterClose: () => { // afterClose: () => {
mediaDom.remove(); // mediaDom.remove();
// clearInterval(interval); // // clearInterval(interval);
}, // },
classNames: { body: "photos-bodyBox" }, // classNames: { body: "photos-bodyBox" },
}); // });
}; // };
const handleShowVideo = (video) => { const handleShowVideo = (video) => {
Dialog.className = "videoMask"; Dialog.className = "videoMask";
Dialog.show({ Dialog.show({
@ -354,7 +359,7 @@ export default function Photos({
); );
})} })}
</div> </div>
{/* <ImagesMask ref={imagesMaskRef}/> */} <ImagesMask ref={imagesMaskRef} />
{/* <Viewer {/* <Viewer
visible={visible} visible={visible}
onClose={() => { setVisible(false); } } onClose={() => { setVisible(false); } }