4 글 보임 - 1 에서 4 까지 (총 4 중에서)
-
글쓴이글
-
2023년 4월 10일 22:40 #75500
정중식참가자저번에 선생님께 질문을드렸는데, 선생님이 알려주신곳 을 참고해서 다음과 같이 작성해봤습니다. 먼저 , Gallery.tsx입니다.
import React, { useRef } from 'react'; import styled from 'styled-components'; import { useScroll } from '../utils/useScroll'; import { photos } from '../utils/photos';
const Container = styled.div` background: #000; overflow: hidden; `;
const List = styled.ul` overflow-x: hidden; display: flex; position: sticky; top: 0; `;
const Item = styled.li` min-width: 50vw; min-height: 100vh; display: flex; justify-content: center; align-items: center; font-size: 4ch;</pre> <pre> :nth-child(even) { background-color: teal; color: white; }</pre> <pre> img { max-width: 100%; /* height: 500px; */ height: 200px; } `; // const Item = styled.li` // margin: 0.5rem; // min-width: 35vw; // position: relative; // display: flex; // justify-content: center; // align-items: center;</pre> <pre>// img { // max-width: 100%; // /* height: 500px; */ // height: 200px; // } // `;
const Gallery = () => { const containRef = useRef<HTMLDivElement>(null); const scrollRef = useScroll(containRef);
return ( <Container ref={containRef}> <List ref={scrollRef}> {photos.map((photo) => ( <Item key={photo.id}> < img src={photo.src} alt='' /> </Item> ))} </List> </Container> ); };
export default Gallery;
다음은 useScroll.tsx 입니다.
import { useRef, useEffect } from 'react';
export function useScroll(containRef: any) { const elRef = useRef<any>();
useEffect(() => { const el = elRef.current; const container = containRef.current;
if (el) { const setStickyContainersSize = () => { if (container) { const stickyContainerHeight = container.scrollWidth;
container.setAttribute( 'style', 'height: ' + stickyContainerHeight + 'px' ); } };
const isElementInViewport = (el: any) => { const rect = el.getBoundingClientRect();
return ( rect.top <= 0 && rect.bottom > document.documentElement.clientHeight ); };
setStickyContainersSize();
const onWheel = (e: any) => { if (e.deltaY === 0) return; const containerInViewPort = isElementInViewport(container);
if (!containerInViewPort) { return; }
e.preventDefault();
var isPlaceHolderBelowTop = el.offsetTop < document.documentElement.scrollTop; var isPlaceHolderBelowBottom = el.offsetTop + el.offsetHeight > document.documentElement.scrollTop; let g_canScrollHorizontally = isPlaceHolderBelowTop && isPlaceHolderBelowBottom;
if (g_canScrollHorizontally) { el.scrollTo({ left: el.scrollLeft + e.deltaY, // behavior: strength > 70 ? 'auto' : 'smooth', }); } };
el.addEventListener('wheel', onWheel);
return () => { el.removeEventListener('wheel', onWheel); }; } }, [containRef]); return elRef; }
이렇게 작성했는데 동작이 조금 거시기해서요...
https://youtu.be/P1rLgQLQEcw 뭐라고해야할까요.. 이곳 처럼 스크롤을 쭉 쭉 내리다가 해당 요소에 화면이 닿으면 가로로 쭉쭉 내려가지만 스크롤은 세로로 내려가고있어야하고, 가로스크롤이끝나면 그대로 아래로 내려가게끔 해주고싶은데 아.. 이틀을 붙잡고있었는데 제 머리론 방안이 도저히 안떠오르네요.. 선생님 그리고 추가로 setStickyContainersSize 함수를 꼭 써줘야하나요? (필요없을거같아서 함수를 삭제하고 실행해봤는데 불안정하게 동작하던 가로스크롤도 아예안되네요.)
2023년 4월 11일 10:57 #75547
codingapple키 마스터원하는 사이트는 position sticky만 대충 주고 스크롤양에 비례해서 transform : translateX를 수정시켜서 박스를 왼쪽이동시켜준거같군요
2023년 4월 11일 21:50 #75643
정중식참가자센세.. 코드를 이런식으로 쳤는데요
const containRef = useRef<HTMLDivElement>(null); const scrollRef = useRef<any>(null);
useEffect(() => { const onScroll = () => { if (scrollRef.current && containRef.current) { let viewWidth = window.innerWidth; let galleryPosition = containRef.current.offsetTop; let scrollLocation = document.documentElement.scrollTop;
if ( viewWidth >= 768 && scrollLocation >= galleryPosition && scrollLocation < galleryPosition + 4000 ) { let percent = ((scrollLocation - galleryPosition) / 4000) * -80; scrollRef.current.style.transform = 'translateX(' + percent + '%)'; } } }; window.addEventListener('scroll', onScroll);
return () => { window.removeEventListener('scroll', onScroll); }; }, []); 영상 이렇게 나옵니다. 포지션 스티키가 안먹는것같은데 혹시 제가 스크롤양에 비례해서 이동시켜주는 코드를 잘못짰을까요? 전체코드는 이렇습니다.
import React, { useRef, useEffect } from 'react'; import styled from 'styled-components'; import { photos } from '../utils/photos';
const Container = styled.section` background-color: #edf2f4; width: 100vw;</pre> <pre> @media (min-width: 768px) { height: 4000px; } `;
const Wrapper = styled.div` position: sticky; overflow: hidden; padding-top: 6.25rem; top: 0; width: 100%; `;
const List = styled.ul` @media (min-width: 768px) { width: 4000px; height: 100vh; display: flex; flex-direction: row; justify-content: space-around; align-items: stretch; flex-wrap: nowrap; } `;
const Item = styled.li` @media (min-width: 768px) { :nth-child(odd) { display: flex; flex-direction: row; justify-content: space-around; align-items: flex-end; flex-wrap: nowrap; }</pre> <pre> :nth-child(1) { width: 18.75rem; height: 100%; }</pre> <pre> &:nth-child(2) { img { height: 31.25rem; overflow: hidden; object-fit: cover; } }</pre> <pre> &:nth-child(3) { img { height: 31.25rem; width: 43.75rem; transform: translateY(-25vh); overflow: hidden; object-fit: cover; } } }</pre> <pre> img { max-width: 100%; border-radius: 0.625rem; box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.3);</pre> <pre> @media (min-width: 768px) { width: clamp(500px px, 50% + 20px, 900px); transform: translateX(-1%); } } `;
const Gallery = () => { const containRef = useRef<HTMLDivElement>(null); const scrollRef = useRef<any>(null);
useEffect(() => { const onScroll = () => { if (scrollRef.current && containRef.current) { let viewWidth = window.innerWidth; let galleryPosition = containRef.current.offsetTop; let scrollLocation = document.documentElement.scrollTop;
if ( viewWidth >= 768 && scrollLocation >= galleryPosition && scrollLocation < galleryPosition + 4000 ) { let percent = ((scrollLocation - galleryPosition) / 4000) * -80; scrollRef.current.style.transform = 'translateX(' + percent + '%)'; } } }; window.addEventListener('scroll', onScroll);
return () => { window.removeEventListener('scroll', onScroll); }; }, []);
return ( <Container ref={containRef}> <Wrapper> <List ref={scrollRef}> <Item /> {photos.map((photo) => ( <Item key={photo.id}> < img src={photo.src} alt='' /> </Item> ))} </List> </Wrapper> </Container> ); };
export default Gallery;
-
글쓴이글
4 글 보임 - 1 에서 4 까지 (총 4 중에서)
- 답변은 로그인 후 가능합니다.