snap-scroll & scroll된 동영상 재생 (youtube shorts)Frontend/UI&UX2022. 7. 7. 16:19
Table of Contents
What to do?
- snap-scroll을 이용해서 부드러운 스크롤을 구현해보자.
- 스크롤을 조금만 내려도 바로 다음 아이템의 가운데까지 스크롤된 후 멈추게하자!
- 스크롤할 아이템을 감싸는 컨테이너는 scroll-snap-type: y mandatory를 사용!
- 스크롤될 아이템은 scroll-snap-align:center를 사용!
- 유튜브 shorts 처럼 스크롤된 아이템의 가운데 화면이 멈추고 동영상이라면 동영상을 재생시키고 그렇지 않은 동영상들은 중지시키자
- 스크롤되어 화면 가운데에 보이는 동영상만 재생시킴! 사진은 재생 x!
소스코드
App.js
- 스크롤할 아이템을 감싸는 컨테이너의 뷰포트에서 맨 위 Y좌표(snapScrollTopY)와 맨 아래 Y좌표(snapScrollBottomY) 사이에 스크롤될 아이템의 뷰포트에서 중간 좌표(snapScrollItemCenter)가 들어오면 비디오를 재생시키고 그 사이에 있지 않은 아이템은 비디오를 중지시킨다!
- 위 그림 보면 잘 이해될듯?
import "./App.scss";
import {useRef, useState} from "react";
const App = () => {
// snapScrollItem을 담는 wrapper의 ref
const snapScrollWrapperRef = useRef();
const [images, setImages] = useState([
{previewURL: "img/image1.jpg", type: "image"},
{previewURL: "video/video1.mp4", type: "video"},
{previewURL: "img/image2.jpg", type: "image"},
{previewURL: "video/video2.mp4", type: "video"},
{previewURL: "img/image3.png", type: "image"},
]);
const playVideo = (e) => {
// snap-scroll-wrapper의 뷰포트에서 맨 위 Y좌표와 맨 아래 Y좌표를 구함
const snapScrollWrapperRect = e.target.getBoundingClientRect();
const snapScrollWrapperTopY = snapScrollWrapperRect.top;
const snapScrollWrapperBottomY = snapScrollWrapperRect.bottom;
// 스크롤되는 아이템들은 snap-scoll-wrapper의 자식들(snap-scroll-item)이다.
const snapScrollItems = e.target.childNodes;
snapScrollItems.forEach((item) => {
// 이미지나 비디오는 snap-scroll-item의 0번째 자식
const snapScrollItem = item.childNodes[0];
// 비디오일 때만 부모의 뷰포트 맨위와 맨 아래에 중심이 들어왔을 때 실행
if (snapScrollItem.tagName === "VIDEO"){
const snapScrollItemRect = item.childNodes[0].getBoundingClientRect();
// snapScrollItem의 뷰포트에서 중앙 Y 좌표
const snapScrollItemCenter = (snapScrollItemRect.top + snapScrollItemRect.bottom) / 2;
if (snapScrollItemCenter > snapScrollWrapperTopY &&
snapScrollItemCenter < snapScrollWrapperBottomY
) {
snapScrollItem.play();
}
else{
snapScrollItem.pause();
}
}
})
}
return (
<>
<div className="header">
THIS IS HEADER!!
</div>
<div className="snap-scroll-wrapper" ref={snapScrollWrapperRef} onScroll={playVideo}>
{images.map((item, index) => (
<div className="snap-scroll-item" key={index}>
{item.type === "image" ? (
<img src={item.previewURL}/>
) : (
<video src={item.previewURL} controls={true} muted={true}/>
)}
</div>
))}
</div>
</>
);
}
export default App;
App.scss
- 한 화면에 하나의 비디오나 이미지가 들어오게 하기 위해서 헤더를 제외한 뷰포트의 전체 높이를 스크롤될 아이템들을 감싸는 컨테이너와 스크롤될 아이템을 위한 공간으로 사용한다!
- (전체 높이 - 헤더의 높이)를 계산해서 높이를 부여하는 부분을 잘 염두해두자!
// snap-scroll-wrapper에서 %높이를 사용하려면 여기서 먼저 높이를 지정해야함
// body는 기본적으로 높이값이 없기 때문에 높이를 줘야함
html, body {
height: 100%;
}
//body의 자식인 root도 height를 먹여줌
#root {
height: 100%;
}
body {
margin: 0;
padding: 0;
}
// header 높이 계산
:root {
--header--height: 100px
}
.header {
position: fixed;
top: 0;
left: 0;
background: gray;
height: var(--header--height);
display: flex;
justify-content: center;
align-items: center;
width: 100%;
font-size: 2rem;
color: #ffffff;
}
.snap-scroll-wrapper {
position: relative;
// header가 fixed이므로 relative 속성을 주고 header 높이만큼 top 값을 부여
top: var(--header--height);
// header 높이를 제외한 나머지는 모두 높이
height: calc(100% - var(--header--height));
// y축 snap-scroll
scroll-snap-type: y mandatory;
overflow: auto;
.snap-scroll-item {
height: 80%;
width: 350px;
// 이미지 border 밖으로 나가는거 자르기
overflow: hidden;
background: black;
border-radius: 20px;
// item의 가운데 스크롤이 멈추게
scroll-snap-align: center;
// 가운데 정렬 및 위아래 margin
margin: 2rem auto;
img, video{
width: 100%;
height: 100%;
// 비율 유지하면서 최대한 포함 시키기 확대x
object-fit: contain;
}
}
}
'Frontend > UI&UX' 카테고리의 다른 글
carousel 만들기 (0) | 2022.07.20 |
---|---|
이미지&비디오 여러개 업로드 - 미리보기/시간제한/삭제 (0) | 2022.07.05 |
비디오&이미지 업로더 - 미리보기/시간 제한 (0) | 2022.07.01 |
react-dnd → Drag & Drop (1) | 2022.06.30 |
tailwind-css (0) | 2022.06.11 |
@덕구공 :: Duck9s'
주니어 개발자에욤
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!