11日目
41121 ワード
1.image-crouselの実装
最初は
本人の理解に沿って整理する
1.最後のイメージを最初に追加します.
2.最後尾に最初の画像を追加します.
3.改行せずに横並びで画像を配置します.(
4.右クリックして
さらに理解する必要がある
1.右側でも左側でも、終了時にボタンを押して、最初に追加した画像を表示します.(上図定理1,2の原因)
2.画像移動終了後に
説明の理解
画像名が1,2,3の場合、
(
その後、
これにより、ユーザは、何の変化もなく、内部から
逆もまた然り.
次に、画像を移動する矢印または現在の位置を示す変数を追加します. /components/common/ImageCarousel/index.jsx リファレンスサイト
反応炉の実施
バニラJSで実現 の最後の部分
1.難点と解決方法
実装中は、導入イメージの場所が容易ではなく、機能の実現が困難なため、時間がかかります.
また、
また、
image-carousel
を直接実施し,後で適用することにした.最初は
react-slick
を使いたかったのですが、使い方を学ぶよりも、まず原理を理解して自分で実施してからライブラリを使うほうがいいと思いますので、googlingで原理を理解して自分で実施しました.本人の理解に沿って整理する
1.最後のイメージを最初に追加します.
2.最後尾に最初の画像を追加します.
3.改行せずに横並びで画像を配置します.(
overflow: hidden
)4.右クリックして
transform: translateX(100%)
に移動します.(transition
適用),(左と反対)さらに理解する必要がある
1.右側でも左側でも、終了時にボタンを押して、最初に追加した画像を表示します.(上図定理1,2の原因)
2.画像移動終了後に
transition
を一旦閉じ、1番目の画像に移動してtransition
を開く.説明の理解
画像名が1,2,3の場合、
[3-1, 1, 2, 3, 1-1]
の順に展開される.(
3-1
、1-1
と記載されている.)その後、
3
から1-1
に右に移動します.1-1
のtransition
が終了した後、transition
を閉じ、1-1
から1
に移動し、さらにtransition
を開く.これにより、ユーザは、何の変化もなく、内部から
1
に移行したため、無限の画像を見ることができる.逆もまた然り.
// 2021/12/23 - image-carousel ( 게시글 읽기 모달 and 게시글 생성 모달에 사용 ) - by 1-blue
import React, { useCallback, useEffect, useRef, useState } from "react";
import Proptypes from "prop-types";
// styled-components
import { Wrapper } from "./style";
const ImageCarousel = ({ children, speed, length, height }) => {
const wrapperRef = useRef(null);
const dotRef = useRef(null);
const [imageNodes, setImageNodes] = useState(null);
const [dotNodes, setDotNodes] = useState(null);
const [currentIndex, setCurrentIndex] = useState(1);
const [click, setClick] = useState(true);
// 2021/12/23 - 이미지 노드들 배열로 모아서 state에 넣는 함수 - by 1-blue
useEffect(() => {
setImageNodes([...wrapperRef.current.childNodes]);
}, [wrapperRef.current]);
// 2021/12/23 - 첫 이미지 지정 - by 1-blue
useEffect(() => {
imageNodes?.forEach(imageNode => (imageNode.style.transform = `translateX(-${currentIndex * 100}%)`));
setTimeout(() => {
imageNodes?.forEach(imageNode => (imageNode.style.transition = `all ${speed}ms`));
}, 100);
}, [imageNodes]);
// 2021/12/23 - 다음 이미지로 넘기는 함수 - by 1-blue
const onClickNextButton = useCallback(() => {
if (!click) return;
// dot 모두 초기화 ( 이전에 이동이 앞인지 뒤인지 알 수 없으니 모두 초기화 )
dotNodes.forEach(dotNode => (dotNode.style.color = "white"));
// 이미지 변경
imageNodes.forEach(imageNode => (imageNode.style.transform = `translateX(-${(currentIndex + 1) * 100}%)`));
setCurrentIndex(prev => (prev + 1 === imageNodes.length - 1 ? 1 : prev + 1));
// 마지막 이미지에서 다음버튼을 누를 경우 실행
if (currentIndex + 1 === imageNodes.length - 1) {
setClick(false);
setTimeout(() => {
imageNodes.forEach(imageNode => (imageNode.style.transition = `all 0s`));
}, 900);
setTimeout(() => {
imageNodes.forEach(imageNode => (imageNode.style.transform = `translateX(-${1 * 100}%)`));
}, 1000);
setTimeout(() => {
imageNodes.forEach(imageNode => (imageNode.style.transition = `all ${speed}ms`));
setClick(true);
}, 1010);
// 현재 이미지와 dot 동기화
dotNodes[currentIndex - length].style.color = "black";
} else {
// 현재 이미지와 dot 동기화
dotNodes[currentIndex].style.color = "black";
}
}, [imageNodes, currentIndex, click, dotNodes, length]);
// 2021/12/23 - 이전 이미지로 넘기는 함수 - by 1-blue
const onClickPrevButton = useCallback(() => {
if (!click) return;
// dot 모두 초기화 ( 이전에 이동이 앞인지 뒤인지 알 수 없으니 모두 초기화 )
dotNodes.forEach(dotNode => (dotNode.style.color = "white"));
imageNodes.forEach(imageNode => (imageNode.style.transform = `translateX(-${(currentIndex - 1) * 100}%)`));
setCurrentIndex(prev => (prev - 1 === 0 ? imageNodes.length - 2 : prev - 1));
// 첫 이미지에서 이전버튼을 누를 경우 실행
if (currentIndex - 1 === 0) {
setClick(false);
setTimeout(() => {
imageNodes.forEach(imageNode => (imageNode.style.transition = `all 0s`));
}, 250);
setTimeout(() => {
imageNodes.forEach(imageNode => (imageNode.style.transform = `translateX(-${(imageNodes.length - 2) * 100}%)`));
}, 500);
setTimeout(() => {
imageNodes.forEach(imageNode => (imageNode.style.transition = `all ${speed}ms`));
setClick(true);
}, 510);
// 현재 이미지와 dot 동기화
dotNodes[length - 1].style.color = "black";
} else {
// 현재 이미지와 dot 동기화
dotNodes[currentIndex - 2].style.color = "black";
}
}, [imageNodes, currentIndex, click, dotNodes, length]);
// 2021/12/23 - dot 노드들 배열로 모아서 state에 넣는 함수들 - by 1-blue
useEffect(() => {
setDotNodes([...dotRef.current.childNodes]);
}, [dotRef.current]);
// 2021/12/23 - 첫 이미지와 dot 동기화 - by 1-blue
useEffect(() => {
if (!dotNodes) return;
dotNodes[0].style.color = "black";
}, [dotNodes]);
return (
<Wrapper height={height}>
{/* 이미지들 */}
<ul ref={wrapperRef} className="image-container">
{children}
</ul>
{/* 이미지 이동 버튼 */}
<button type="button" onClick={onClickNextButton} className="next-button">
{">"}
</button>
<button type="button" onClick={onClickPrevButton} className="prev-button">
{"<"}
</button>
{/* 이미지 현재 위치를 표시하는 노드들 */}
<ul className="dots" ref={dotRef}>
{Array(length)
.fill()
.map((v, i) => (
<li key={i}>•</li>
))}
</ul>
<span className="image-number">{`${currentIndex} / ${length}`}</span>
</Wrapper>
);
};
ImageCarousel.propTypes = {
children: Proptypes.node.isRequired,
speed: Proptypes.number,
height: Proptypes.number,
};
ImageCarousel.defaultProps = {
speed: 1000,
height: 100,
};
export default ImageCarousel;
反応炉の実施
バニラJSで実現
1.難点と解決方法
実装中は、導入イメージの場所が容易ではなく、機能の実現が困難なため、時間がかかります.
また、
transition
を閉じて画像を移動したが、常にtransition
の問題に遭遇し、原因を特定できないため、setTimeout
を使用して問題を解決し、順番に実行した.また、
currentIndex
を用いて現在の画像が何であるかを判断し、state
の値がcurrentIndex
なのか+1
なのか、どのような計算を適用すれば正常に動作するのか、混乱させ、理解するよりも、一つ一つ適用して問題を解決する方がよい.Reference
この問題について(11日目), 我々は、より多くの情報をここで見つけました https://velog.io/@1-blue/bluegram-11일차テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol