React에서 어셈블리 간의 컨텐트에 대한 애니메이션 설정하기
TL;박사 01 명
내 방법의 고급 보기는 사용자가 자원을 눌렀을 때 새 구성 요소로 애니메이션화하는 것이다.이 점을 실현하기 위해서, 나는 자원을 새 구성 요소에서 상태 변화를 보이고, CSS를 사용하여 그것들을 원시 위치로 강제로 돌려보내고, 그것들을 새 위치의 애니메이션으로 설정했다.코드를 깊이 있게 이해하고 결과를 보기만 한다면 code pen 또는 본문 말미에서 전체 코드를 볼 수 있습니다.
설정
나는 가능한 한 이 문제를 줄여서 더욱 쉽게 해결했다.다음은 미리 애니메이션된 장면의 기본 템플릿 코드입니다.
//App.js
const FarmFig = ({ image, handleClick=null, setRef }) => {
return (
<img className="image" src={image} ref={setRef} onClick={handleClick} />
);
};
class App extends React.Component {
constructor(){
super()
this.center = React.createRef();
this.state = {
this.state = {
images: {
tl:
"https://lh3.googleusercontent.com/proxy/YSIR4H4fU2Tf5vmbmeixy6m6ZcTXvS9wEo8q4gxOiqEg8XXPod1ZaGJbc8-wngYJwkR6QHEfjvO3w4QogZJqVH5nJjhJaMk",
c:
"https://lh3.googleusercontent.com/proxy/29-YDS42UPIZNuPicKnpkmh2sw_th3Sa41d6iiGT8XH1vXfjfpNgUCK1-CxlMlT40eaJP25ylJ8IRUiCEBwTfIyuBB8izJ8",
br:
"https://pngarchive.com/public/uploads/small/11559054782q4dsokodad1svijk1zzlyrjdwtmlygkkaxxvooeqevdyrbomu3b5vwcwst0ndcidr89gdf0nyleyffoncphgazeqmnpmdubfypow.png",
},
}
}
handleClick = ({target}) => {
this.setState(prevState => {
//switch clicked image with the center image
if (prevState.images.tl === target.src) {
prevState.images.tl = prevState.images.c;
prevState.images.c = target.src
} else {
prevState.images.br = prevState.images.c;
prevState.images.c = target.src
}
return {images: prevState.images}
})
}
render() {
const{tl, c, br} = this.state.images
return (
<div className="container">
<div className="top-left">
<FarmFig image={tl} handleClick={this.handleClick}/>
</div>
<div className="container">
<FarmFig image={c} setRef={this.center} />
</div>
<div className="bot-right">
<FarmFig image={br} handleClick={this.handleClick} />
</div>
</div>
)
}
}
/* css */
.container {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
justify-content: center;
height: 90vh;
width: 100%;
}
.top-left {
align-self: flex-start;
transform: rotate(180deg)
}
.bot-right {
align-self: flex-end;
}
.image {
width: 175px;
}
지금까지 기본적으로 이미 준비가 다 되었다.우리는 세 장의 사진이 있다. 왼쪽 위, 중간, 오른쪽 아래.왼쪽 상단이나 오른쪽 하단의 그림을 클릭하면, 클릭한 그림과 중심 그림을 교환하는 상태 변화를 촉발합니다.우리는 또한
ref
중심에 있는 그림을 포함하여 곧 그것을 사용할 것이다.이제 이 과도 애니메이션을 만들어 봅시다.애니메이션 추가
이미지에 애니메이션 효과를 적용하려면 먼저 상태에 항목을 추가해야 합니다.
this.state = {
images: {
tl:
"https://lh3.googleusercontent.com/proxy/YSIR4H4fU2Tf5vmbmeixy6m6ZcTXvS9wEo8q4gxOiqEg8XXPod1ZaGJbc8-wngYJwkR6QHEfjvO3w4QogZJqVH5nJjhJaMk",
c:
"https://lh3.googleusercontent.com/proxy/29-YDS42UPIZNuPicKnpkmh2sw_th3Sa41d6iiGT8XH1vXfjfpNgUCK1-CxlMlT40eaJP25ylJ8IRUiCEBwTfIyuBB8izJ8",
br:
"https://pngarchive.com/public/uploads/small/11559054782q4dsokodad1svijk1zzlyrjdwtmlygkkaxxvooeqevdyrbomu3b5vwcwst0ndcidr89gdf0nyleyffoncphgazeqmnpmdubfypow.png",
},
animate: true,
transition: {
center: {
startTop: 0,
startRight: 0,
},
corner: {
farmItem: null,
startTop: 0,
startRight: 0,
},
},
};
이미지를 다시 렌더링한 후 조정된 시작 위치를 추적하기 위해 transition
객체를 추가했습니다.교환된 이미지를 새 어셈블리에서 렌더링하고 원래 위치로 이동한 다음 새 위치로 애니메이션화합니다.다음에 우리는 그림을 클릭한 후에 이 조정된 시작 위치를 계산해야 한다.이것은 우리의
handlClick
함수에서 완성될 것이다. handleClick = ({ target }) => {
// find location of clicked image
const imageStartTop =
target.getBoundingClientRect().top + document.documentElement.scrollTop;
const imageStartRight =
target.getBoundingClientRect().right +
document.documentElement.scrollLeft;
//find ending location of clicked image
let endLoc = this.getCenterLoc();
let selectedImage;
this.setState((prevState) => {
if (prevState.images.tl === target.src) {
// Swap the selected and center images
selectedImage = "tl";
prevState.images.tl = prevState.images.c;
prevState.images.c = target.src;
} else {
selectedImage = "br";
prevState.images.br = prevState.images.c;
prevState.images.c = target.src;
}
return {
images: prevState.images,
// We set animate to false to temporarily to allow images to relocate
animate: false,
transition: {
center: {
// y distance in px the center image needs to move
startTop: imageStartTop - endLoc[0],
// x distance in px the center image needs to move
startRight: imageStartRight - endLoc[1],
},
corner: {
farmItem: selectedImage,
// y distance in px the clicked image needs to move
startTop: endLoc[0] - imageStartTop,
// y distance in px the clicked image needs to move
startRight: endLoc[1] - imageStartRight,
},
},
};
});
// Wait briefly then change the animation flag to trigger a re-render and the animation.
setTimeout(() => this.setState({ animate: true }), 200);
};
어디:getCenterLoc = () => {
const imageEndTop =
this.center.current.getBoundingClientRect().top +
document.documentElement.scrollTop;
const imageEndRight =
this.center.current.getBoundingClientRect().right +
document.documentElement.scrollLeft;
return [imageEndTop, imageEndRight];
};
이곳에서 많은 일이 발생했지만, 결국 이것은 번거로운 감법 문제일 뿐이다.우리는 뷰포트를 기준으로 클릭 및 중심 이미지의 위치를 얻기 위해 중심 이미지ref
와 클릭한 이벤트 대상을 사용합니다.element.getBoundingClientRect()
는 문서에 대한 좌표를 제시하고 페이지가 굴러갈 경우 문서의 편향을 추가element
합니다.그런 다음 중심 이미지와 선택한 이미지 사이의 차이에 따라 상태를 설정합니다.그 다음에 우리는
document.documentElement.scrollTop
를 사용하여 상태에서 setTimeout
로고를 변경하고 애니메이션을 터치하기 전에 잠시 기다립니다.이제 이미지를 클릭할 때 새 위치를 적용해야 합니다.우리의 렌더링 방법에서, 우리는 삼원 함수를 추가하여
animate
속성을 검사할 것이다const animClass = this.state.animate ? "force-move" : "";
그리고 우리는 이 새로운 클래스와 조정된 위치를 해당하는 this.state.animate
구성 요소에 전달하고 FarmFig
와 CSS 파일을 다음과 같이 업데이트할 수 있다.const FarmFig = ({ image, handleClick = null, setRef, locs, animClass }) => {
return (
<img
className={`image ${animClass}`}
src={image}
ref={setRef}
onClick={handleClick}
style={{
transform: `translate(${locs[1]}px, ${locs[0]}px)`,
}}
/>
);
};
.force-move {
transition: transform 1s;
transition-delay: 1s;
transform: translate(0, 0) !important;
}
후..드디어 저희가 이동 애니메이션이 생겼어요!!!이거 좋아요.나는 처음에 공간을 가로지르는 것이 아니라 공간에서 부분을 이동하는 애니메이션이 필요했다.불행하게도 CSS는 같은 대상의 여러 종류
FarmFig
사이에서 지연을 설정하는 것을 지원하지 않습니다.나의 해결 방안은 transforms
divs
주위에 추가FarmFig
를 추가하고 시간이 지연된 모든 사람을 바꾸는 것이다. (이것은 틀림없이 좀 불편하게 느낄 것이다. 누가 더 좋은 생각이 있습니까?)마지막으로 Dell
img
및 CSS 파일을 업데이트합니다.<div
className={`${animClass}X`}
style={{
transform: `translate(${locs[1]}px`,
}}
>
<div
className={`${animClass}Y`}
style={{
transform: `translateY(${locs[0]}px)`,
}}
>
<img
className={`image`}
src={image}
ref={setRef}
onClick={handleClick}
/>
...
.force-moveX {
transition: transform 1s;
transform: translate(0) !important;
}
.force-moveY {
transition: transform 1s;
transition-delay: 1s;
transform: translateY(0) !important;
}
봐라!마무리
부인할 수 없습니다. CSS만 사용하여 React에서 사용자 정의 애니메이션을 구축하는 것은 상당히 많은 코드가 필요합니다.물론 모든 상황이 다 적용되는 것은 아니다.그러나 프로젝트에 의존하는 라이브러리의 수량을 제한하고 싶다면 독특한 용례가 있거나 CSS에 직면할 때가 됐다고 결정하면 된다.도움이 됐으면 좋겠어요. 제가 뭘 완전히 망치면!
전체 코드
코드 펜
비밀 번호
// App.js
const FarmFig = ({ image, handleClick = null, setRef, locs, animClass }) => {
return (
<div
className={`${animClass}X`}
style={{
transform: `translate(${locs[1]}px`,
}}
>
<div
className={`${animClass}Y`}
style={{
transform: `translateY(${locs[0]}px)`,
}}
>
<img
className={`image`}
src={image}
ref={setRef}
onClick={handleClick}
/>
</div>
</div>
);
};
class App extends React.Component {
constructor() {
super();
this.center = React.createRef();
this.state = {
images: {
tl:
"https://lh3.googleusercontent.com/proxy/YSIR4H4fU2Tf5vmbmeixy6m6ZcTXvS9wEo8q4gxOiqEg8XXPod1ZaGJbc8-wngYJwkR6QHEfjvO3w4QogZJqVH5nJjhJaMk",
c:
"https://lh3.googleusercontent.com/proxy/29-YDS42UPIZNuPicKnpkmh2sw_th3Sa41d6iiGT8XH1vXfjfpNgUCK1-CxlMlT40eaJP25ylJ8IRUiCEBwTfIyuBB8izJ8",
br:
"https://pngarchive.com/public/uploads/small/11559054782q4dsokodad1svijk1zzlyrjdwtmlygkkaxxvooeqevdyrbomu3b5vwcwst0ndcidr89gdf0nyleyffoncphgazeqmnpmdubfypow.png",
},
animate: true,
transition: {
center: {
startTop: 0,
startRight: 0,
},
corner: {
farmItem: null,
startTop: 0,
startRight: 0,
},
},
};
}
getCenterLoc = () => {
const imageEndTop =
this.center.current.getBoundingClientRect().top +
document.documentElement.scrollTop;
const imageEndRight =
this.center.current.getBoundingClientRect().right +
document.documentElement.scrollLeft;
return [imageEndTop, imageEndRight];
};
handleClick = ({ target }) => {
// find location of clicked image
const imageStartTop =
target.getBoundingClientRect().top + document.documentElement.scrollTop;
const imageStartRight =
target.getBoundingClientRect().right +
document.documentElement.scrollLeft;
//find location of ending location
let endLoc = this.getCenterLoc();
let selectedImage;
this.setState((prevState) => {
if (prevState.images.tl === target.src) {
selectedImage = "tl";
prevState.images.tl = prevState.images.c;
prevState.images.c = target.src;
} else {
selectedImage = "br";
prevState.images.br = prevState.images.c;
prevState.images.c = target.src;
}
return {
images: prevState.images,
animate: false,
transition: {
center: {
startTop: imageStartTop - endLoc[0],
startRight: imageStartRight - endLoc[1],
},
corner: {
farmItem: selectedImage,
startTop: endLoc[0] - imageStartTop,
startRight: endLoc[1] - imageStartRight,
},
},
};
});
setTimeout(() => this.triggerAnim(), 200);
};
triggerAnim = () => {
this.setState({ animate: true });
};
getOldLoc = (loc) => {
const { corner } = this.state.transition;
let top, right;
if (corner.farmItem === loc) {
top = corner.startTop;
right = corner.startRight;
} else {
top = 0;
right = 0;
}
return [top, right];
};
render() {
const { tl, c, br } = this.state.images;
const { center } = this.state.transition;
const animClass = this.state.animate ? "force-move" : "";
return (
<div className="container">
<div className="top-left">
<FarmFig
image={tl}
handleClick={this.handleClick}
locs={this.getOldLoc("tl")}
animClass={animClass}
/>
</div>
<div className="center">
<FarmFig
image={c}
setRef={this.center}
locs={[center.startTop, center.startRight]}
animClass={animClass}
/>
</div>
<div className="bot-right">
<FarmFig
image={br}
handleClick={this.handleClick}
locs={this.getOldLoc("br")}
animClass={animClass}
/>
</div>
</div>
);
}
}
\* css *\
.container {
display: flex;
flex-direction: row;
justify-content: space-between;
height: 90vh;
width: 100%;
}
.center {
align-self: center;
}
.top-left {
align-self: flex-start;
}
.bot-right {
align-self: flex-end;
}
.image {
width: 150px;
height: 130px;
}
.force-moveX {
transition: transform 1s;
transform: translate(0) !important;
}
.force-moveY {
transition: transform 1s;
transition-delay: 1.5s;
transform: translateY(0) !important;
}
Reference
이 문제에 관하여(React에서 어셈블리 간의 컨텐트에 대한 애니메이션 설정하기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/wlytle/animating-content-between-components-in-react-1de5텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)