自定义图片滚动组件

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

View File

@ -10,12 +10,32 @@ import React, {
import { Mask, Image } from "antd-mobile";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
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) {
const [currentIndex, setCurrentIndex] = useState(0);
const [visible, setVisible] = useState(false);
const [images, setImages] = useState([]);
const [distance, setDistance] = useState(0);
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(() => {
if (scrollRef.current) {
setTimeout(() => {
@ -27,91 +47,91 @@ function ImagesMask({}, ref) {
show: (arr, index) => {
setCurrentIndex(index);
setImages(arr);
setVisible(true);
setVisible(old=>{
console.log(arr, index,old)
return !old
});
// Mask.show
// const maskDomBox = document.getElementById("maskDomBox");
},
close: () => setVisible(false),
}));
const getDistance = (e) => {
e.stopPropagation();
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>
);
return <></>;
}
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);

View File

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