add waterfall pic wall
This commit is contained in:
		| @@ -24,7 +24,6 @@ | |||||||
|     "sass": "^1.58.0", |     "sass": "^1.58.0", | ||||||
|     "unstated-next": "^1.1.0", |     "unstated-next": "^1.1.0", | ||||||
|     "uuid": "^9.0.0", |     "uuid": "^9.0.0", | ||||||
|     "waterfalljs-layout": "^0.1.0", |  | ||||||
|     "web-vitals": "^2.1.4" |     "web-vitals": "^2.1.4" | ||||||
|   }, |   }, | ||||||
|   "scripts": { |   "scripts": { | ||||||
|   | |||||||
| @@ -33,7 +33,7 @@ | |||||||
|   justify-content: start; |   justify-content: start; | ||||||
| } | } | ||||||
| .projects__title { | .projects__title { | ||||||
|   margin: 20px 0 0 20px; |   margin: 20px 0 20px 20px; | ||||||
|   font-family: itrFontMedium; |   font-family: itrFontMedium; | ||||||
|   color: #fff; |   color: #fff; | ||||||
|   text-align: center; |   text-align: center; | ||||||
| @@ -49,8 +49,10 @@ | |||||||
|   width: 100vw; |   width: 100vw; | ||||||
|   height: auto; |   height: auto; | ||||||
|   display: flex; |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|   justify-content: center; |   justify-content: center; | ||||||
|   align-items: center; |   align-items: center; | ||||||
|  |   padding-top: 24px; | ||||||
| } | } | ||||||
|  |  | ||||||
| .project__content__main__container { | .project__content__main__container { | ||||||
| @@ -58,7 +60,6 @@ | |||||||
|   border-radius: 10px; |   border-radius: 10px; | ||||||
|   background-color: rgb(66, 66, 66); |   background-color: rgb(66, 66, 66); | ||||||
|   box-sizing: border-box; |   box-sizing: border-box; | ||||||
|   height: auto; |  | ||||||
|   display: flex; |   display: flex; | ||||||
|   flex-direction: column; |   flex-direction: column; | ||||||
|   transition: 0.3s; |   transition: 0.3s; | ||||||
|   | |||||||
| @@ -1,20 +1,7 @@ | |||||||
| #react-waterfall-comps li > div { | .waterfallContainer { | ||||||
|   transition: all 0.5s; |  | ||||||
|   position: relative; |  | ||||||
|   border-radius: 10px; |  | ||||||
|   background-color: rgb(66, 66, 66); |  | ||||||
|   padding: 10px; |  | ||||||
|   display: flex; |   display: flex; | ||||||
|   flex-direction: column; |   flex-wrap: wrap; | ||||||
|   transition: 0.3s; |   .waterfallItem { | ||||||
|   cursor: pointer; |     margin: 3px; | ||||||
|   } |   } | ||||||
| #react-waterfall-comps li > div:hover { |  | ||||||
|   transform: translateY(-6px); |  | ||||||
|   box-shadow: 0 30px 50px rgba(0, 0, 0, 0.3); |  | ||||||
|   transition: all 0.3s; |  | ||||||
|   background-color: #666666; |  | ||||||
| } |  | ||||||
| #react-waterfall-comps li > div > img { |  | ||||||
|   width: 100%; |  | ||||||
| } | } | ||||||
| @@ -1,10 +1,9 @@ | |||||||
| import React, { useEffect, useMemo } from "react"; | import React, { useEffect, useMemo } from "react"; | ||||||
| import { AnimationOnScroll } from "react-animation-on-scroll"; |  | ||||||
| import "../assets/stylesheets/project.scss"; | import "../assets/stylesheets/project.scss"; | ||||||
| import { useContainer } from "unstated-next"; | import { useContainer } from "unstated-next"; | ||||||
| import GlobalStore from "../store/global"; | import GlobalStore from "../store/global"; | ||||||
| import { Image } from 'antd'; | import projects from "../assets/data/projects"; | ||||||
| import projects from '../assets/data/projects'; | import WaterfallPosition from "./Waterfall"; | ||||||
|  |  | ||||||
| const Project = () => { | const Project = () => { | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
| @@ -25,77 +24,14 @@ const Project = () => { | |||||||
|     <div className="project"> |     <div className="project"> | ||||||
|       <div className="project__content"> |       <div className="project__content"> | ||||||
|         <div className="project__content__main"> |         <div className="project__content__main"> | ||||||
|           <AnimationOnScroll |  | ||||||
|             animateIn="animate__fadeInDown" |  | ||||||
|             animateOnce="true" |  | ||||||
|             duration={1} |  | ||||||
|             delay={0} |  | ||||||
|           > |  | ||||||
|             <h1 className="projects__title">Active Projects</h1> |  | ||||||
|             <div className="projects_wrap" size={16}> |  | ||||||
|               {projects.active.map((item) => ( |  | ||||||
|                 <div |  | ||||||
|                   className="project__content__main__container" |  | ||||||
|                   style={{ width: `calc(${100 / count}% - 16px)` }} |  | ||||||
|                 > |  | ||||||
|                   <div style={{ display: 'flex', flexDirection: 'row', justifyContent:'space-between'  }}> |  | ||||||
|                     <h3 style={{ fontFamily: "itrFontMedium", fontSize: '25px', color: "#fff", marginBottom: 12 }}>{item.title}</h3> |  | ||||||
|                     <h3 style={{ fontFamily: "itrFontMedium", fontSize: '25px', color: "#fff", marginBottom: 12 }}>{item.sub}</h3> |  | ||||||
|                   </div> |  | ||||||
|                   <div className="project_item_content"> |  | ||||||
|                     <Image className="project_item_content_image" width={"100%"} src={item.img}></Image> |  | ||||||
|                     <span>{item.content}</span> |  | ||||||
|                   </div> |  | ||||||
|                 </div> |  | ||||||
|               ))} |  | ||||||
|             </div> |  | ||||||
|             <h1 className="projects__title">Retired Projects</h1> |  | ||||||
|             <div className="projects_wrap" size={16}> |  | ||||||
|               {projects.inactive.map((item) => ( |  | ||||||
|                 <div |  | ||||||
|                   className="project__content__main__container" |  | ||||||
|                   style={{ width: `calc(${100 / count}% - 16px)`}} |  | ||||||
|                 > |  | ||||||
|                   <div style={{ display: 'flex', flexDirection: 'row', justifyContent:'space-between'  }}> |  | ||||||
|                     <h3 style={{ fontFamily: "itrFontMedium", fontSize: '25px', color: "#fff", marginBottom: 12 }}>{item.title}</h3> |  | ||||||
|                     <h3 style={{ fontFamily: "itrFontMedium", fontSize: '25px', color: "#fff", marginBottom: 12 }}>{item.sub}</h3> |  | ||||||
|                   </div> |  | ||||||
|                   <div className="project_item_content"> |  | ||||||
|                     <Image className="project_item_content_image" width={"100%"} src={item.img}></Image> |  | ||||||
|                     <span>{item.content}</span> |  | ||||||
|                   </div> |  | ||||||
|                 </div> |  | ||||||
|               ))} |  | ||||||
|             </div> |  | ||||||
|             {/* <div |  | ||||||
|               style={{ |  | ||||||
|                 height: "100vh", |  | ||||||
|                 width: "100vw", |  | ||||||
|                 border: "1px solid", |  | ||||||
|                 marginTop: "30px", |  | ||||||
|                 overflowY: "scroll", |  | ||||||
|               }} |  | ||||||
|             > |  | ||||||
|               <Waterfall |  | ||||||
|                 columnWidth={236} |  | ||||||
|                 columnCount={2} |  | ||||||
|                 columnGap={24} |  | ||||||
|                 rowGap={24} |  | ||||||
|                 onChangeUlMaxH={(h) => (ulMaxHRef.current = h)} |  | ||||||
|               > |  | ||||||
|                 {images.map((item, index) => { |  | ||||||
|                   return ( |  | ||||||
|                     <li key={index} onClick={() => alert("图片地址为:" + item)}> |  | ||||||
|           <div> |           <div> | ||||||
|                         {index + 1} |             <h1 className="projects__title">Active Projects</h1> | ||||||
|                         <img src={item} alt="" /> |             <WaterfallPosition columnNumber={count} list={projects.active} /> | ||||||
|  |           </div> | ||||||
|  |           <div> | ||||||
|  |             <h1 className="projects__title">Retired/Inactive Projects</h1> | ||||||
|  |             <WaterfallPosition columnNumber={count} list={projects.inactive} /> | ||||||
|           </div> |           </div> | ||||||
|                     </li> |  | ||||||
|                   ); |  | ||||||
|                 })} |  | ||||||
|               </Waterfall> |  | ||||||
|             </div> */} |  | ||||||
|           </AnimationOnScroll> |  | ||||||
|         </div> |         </div> | ||||||
|         {/* <WaterfallPositionDemo /> */} |         {/* <WaterfallPositionDemo /> */} | ||||||
|       </div> |       </div> | ||||||
|   | |||||||
| @@ -1,71 +1,95 @@ | |||||||
| import React, { useState, useRef } from "react"; | import { useSize } from "ahooks"; | ||||||
| import Waterfall from "waterfalljs-layout/react"; | import React, { useRef, useEffect, useState } from "react"; | ||||||
| import "../assets/stylesheets/waterfall.scss"; | import "../assets/stylesheets/waterfall.scss"; | ||||||
|  | import { Image } from "antd"; | ||||||
|  |  | ||||||
| const defimages = [ | const WaterfallItem = ({ data, onLoad }) => { | ||||||
|   "https://picsum.photos/640/200/?random", |   const ref = useRef(); | ||||||
|   "https://picsum.photos/360/640/?random", |   const size = useSize(ref); | ||||||
|   "https://picsum.photos/480/720/?random", |   const sizeRef = useRef({}); | ||||||
|   "https://picsum.photos/480/640/?random", |   useEffect(() => { | ||||||
|   "https://picsum.photos/360/?random", |     sizeRef.current.size = size; | ||||||
|   "https://picsum.photos/360/520/?random", |   }, [size]); | ||||||
|   "https://picsum.photos/520/360/?random", |   return ( | ||||||
|   "https://picsum.photos/520/360/?random", |     <div className="waterfallItem" ref={ref}> | ||||||
|   "https://picsum.photos/520/360/?random", |       <div className="project__content__main__container"> | ||||||
|   "https://picsum.photos/720/640/?random", |         <div style={{ display: 'flex', flexDirection: 'row', justifyContent:'space-between'  }}> | ||||||
| ]; |           <h3 style={{ fontFamily: "itrFontMedium", fontSize: '25px', color: "#fff", marginBottom: 12 }}>{data.title}</h3> | ||||||
|  |           <h3 style={{ fontFamily: "itrFontMedium", fontSize: '25px', color: "#fff", marginBottom: 12 }}>{data.sub}</h3> | ||||||
| export default function WaterfallPositionDemo() { |         </div> | ||||||
|   const [images, setImages] = useState(defimages); |         <div className="project_item_content"> | ||||||
|   const ulMaxHRef = useRef(0); |           <Image | ||||||
|  |             onLoad={() => { | ||||||
|   const handleSearchImage = async () => { |               setTimeout(() => { | ||||||
|     function random(min, max) { |                 onLoad(sizeRef.current.size); | ||||||
|       return min + Math.floor(Math.random() * (max - min + 1)); |               }, 500); | ||||||
|     } |             }} | ||||||
|     const arr = []; |             alt="asd" | ||||||
|     for (let i = 0; i < 9; i++) { |             onError={setTimeout(() => { | ||||||
|       const imgSrc = `${defimages[i]}=${random(1, 10000)}`; |               onLoad(sizeRef.current.size); | ||||||
|       arr.push(imgSrc); |             }, 500)} | ||||||
|     } |             width={"100%"} | ||||||
|     setImages((prev) => [...prev, ...arr]); |             src={data.img} | ||||||
|  |           /> | ||||||
|  |           <span>{data.content}</span> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   ); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | const WaterfallPosition = ({ columnNumber, list }) => { | ||||||
|  |   const stateRef = useRef({ | ||||||
|  |     heights: [], | ||||||
|  |     loadNum: 0, | ||||||
|  |   }); | ||||||
|  |   const onload = (index, height) => { | ||||||
|  |     stateRef.current.heights[index] = height; | ||||||
|  |     stateRef.current.loadNum++; | ||||||
|  |     if (stateRef.current.loadNum === list.length) { | ||||||
|  |       onSize(); | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |   const [columns, setColumns] = useState([[], [], [], []]); | ||||||
|  |   const onSize = () => { | ||||||
|  |     let res = [[], [], [], []]; | ||||||
|  |     let columnHeights = [0, 0, 0, 0]; | ||||||
|  |     rendered.map((renderItem, index) => { | ||||||
|  |       let minHeight = Infinity; | ||||||
|  |       let minHeightIndex = 0; | ||||||
|  |       for (let i = 0; i < columnNumber; ++i) { | ||||||
|  |         if (minHeight > columnHeights[i]) { | ||||||
|  |           minHeight = columnHeights[i]; | ||||||
|  |           minHeightIndex = i; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       res[minHeightIndex].push(renderItem); | ||||||
|  |       columnHeights[minHeightIndex] += stateRef.current.heights[minHeightIndex]; | ||||||
|  |     }); | ||||||
|  |     setColumns(res); | ||||||
|  |   }; | ||||||
|  |   const waterfallDOM = useRef(); | ||||||
|  |   const size = useSize(waterfallDOM); | ||||||
|  |   useEffect(() => { | ||||||
|  |     onSize(); | ||||||
|  |   }, [size, columnNumber]); | ||||||
|  |   const rendered = list.map((item, index) => ( | ||||||
|  |     <WaterfallItem onLoad={(size) => onload(index, size.height)} data={item} /> | ||||||
|  |   )); | ||||||
|  |   return ( | ||||||
|  |     <div ref={waterfallDOM} className="waterfallContainer"> | ||||||
|  |       {columns.map((column) => { | ||||||
|         return ( |         return ( | ||||||
|           <div |           <div | ||||||
|             style={{ |             style={{ | ||||||
|         height: "600px", |               width: `calc(${100 / columnNumber}% - 16px)`, | ||||||
|         width: "520px", |  | ||||||
|         border: "1px solid", |  | ||||||
|         marginTop: "30px", |  | ||||||
|         overflowY: "scroll", |  | ||||||
|             }} |             }} | ||||||
|           > |           > | ||||||
|       <Waterfall |             {column} | ||||||
|         columnWidth={236} |  | ||||||
|         columnCount={2} |  | ||||||
|         columnGap={24} |  | ||||||
|         rowGap={24} |  | ||||||
|         onChangeUlMaxH={(h) => (ulMaxHRef.current = h)} |  | ||||||
|       > |  | ||||||
|         {images.map((item, index) => { |  | ||||||
|           return ( |  | ||||||
|             <li key={index} onClick={() => alert("图片地址为:" + item)}> |  | ||||||
|               <div> |  | ||||||
|                 {index + 1} |  | ||||||
|                 <img src={item} alt="" /> |  | ||||||
|           </div> |           </div> | ||||||
|             </li> |  | ||||||
|         ); |         ); | ||||||
|       })} |       })} | ||||||
|       </Waterfall> |  | ||||||
|       <div style={{ textAlign: "center" }}> |  | ||||||
|         <button |  | ||||||
|           onClick={() => handleSearchImage()} |  | ||||||
|           style={{ margin: "30px auto" }} |  | ||||||
|         > |  | ||||||
|           LOAD MORE |  | ||||||
|         </button> |  | ||||||
|       </div> |  | ||||||
|     </div> |     </div> | ||||||
|   ); |   ); | ||||||
| } | }; | ||||||
|  | export default WaterfallPosition; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user