๐ 3d space image carousel with nuxt
Vue ๊ณต๋ถ๋ฅผ ์ํด ๋ง๋ค์ด๋ณธ ํ ์ด ํ๋ก์ ํธ
- ๊ธฐ์ ์คํ : Nuxt, Vue
- ์๋ : Vue ์ฒดํ ๋ฐ ๊ณต๋ถ
- ๋ฐฐํฌ ์ฌ์ดํธ : https://3d-space-carousel.vercel.app/
- ์ฐ๊ธฐ ๋๋ฆ์ด๊ฒ ์ง๋ง, React๋
jsx
๋ฌธ๋ฒ์ผ๋ก html์ ํจ์์ธ์คํด์ค ๋ด๋ถ์์ JavaScript๋ก ๋ชจ๋ ์์ฑํ์๋ค๋ฉด Vue๋template
๋ด๋ถ์์ html๋ฌธ๋ฒ์ ๋ฐ๋ก ์ ์ด์ฃผ์๋ค. ๋ทฐ์ ๋ก์ง์ ์ปดํฌ๋ํธ ๋จ์๋ก ๊ด๋ฆฌํ๋ค๋ ๊ฒ์ ๋น์ทํ ๊ฒ ๊ฐ์๋ค. - React๋
setState
๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝ, ๊ฐ์ง๋ฅผ ํ๋ค๋ฉด, Vue๋ ๋ฐ์ดํฐ๋ฅผ ๊ทธ๋ฅ ๋ฐ๊พธ๋ฉด ์์์ ๊ฐ์งํด์ฃผ๋ ๊ฒ ๊ฐ์๋ค.
- Vue ํ์ผ ๋ด๋ถ์์ styleํ๊ทธ์ scoped ๋ฅผ ์ ์ด์ฃผ๋ฉด ๋ชจ๋ํ๊ฐ ๋ฐ๋ก ๊ฐ๋ฅํ๊ณ , lang="scss"๋ฅผ ์ ์ด์ฃผ๋ฉด ์ ์ฒ๋ฆฌ๊ธฐ๋ ๋ฐ๋ก ์ธ ์ ์์ด์ ์๋นํ ํธํ๋ค. ๋ฌผ๋ก sass๋ฅผ ์ค์นํด์ฃผ์ด์ผ ํ๋ค!
- pages : ํ์ด์ง ์๋ฒ์ฌ์ด๋๋ ๋๋ง๊ณผ ๋ผ์ฐํ
์ ์ง์ํ๋ค. ๋์ ๋ผ์ฐํ
๋
_
์ฐ๋ฉด ๊ฐ๋ฅํ๋ค. - layouts : ํ์ด์ง ๊ณตํต๋ถ๋ถ์ ๊ตฌ์ฑํด์ค๋ค.
<Nuxt/>
์ปดํฌ๋ํธ ์์ผ๋ก page๊ฐ ๋ค์ด๊ฐ๋ ๊ฒ ๊ฐ๋ค. - components : ์ปดํฌ๋ํธ๋ค
- assets, static : ์์ ์ ๋น๋์ ๋ค์ด๊ฐ๋ ์ ์ ํ์ผ, ์คํํฑ์ ๊ทธ๋ ์ง ์์ ์ ์ ํ์ผ์ ์๋ฏธํ๋ ๊ฒ ๊ฐ๋ค. ๊ณต์๋ฌธ์์ ์ฐจ์ด์ ์ด ๋์์๋ค.
- Vue๋ ์๋์ ๋ฐฉ์์ผ๋ก ๋ฐ๋ณต๋ฌธ์ ์ฌ์ฉํ ์ ์์๋ค.
<Component v-for="imageSrc of imageSrcs"
<Component v-for="(imageSrc,index) of imageSrcs"`
- React๋ ์๋์ ๋ฐฉ์์ผ๋ก ๋ฐ๋ณต๋ฌธ์ ์ฌ์ฉํ๋ ๊ฒ์ผ๋ก ๊ธฐ์ตํ๋ค.
{{imageSrcs.map(imageSrc=> <Component>)}}
- props, key, style ๋ฑ๋ก
<Component v-vind:something="value" />
<Component :something="value"/>
- ์ด๋ฒคํธํธ๋ค๋ฌ ๋ฑ๋ก
<Component v-on:eventName="handler"/>
<Component @eventName="handler"/>
<nuxt-link/>
๋ฅผ ์ฐ๋ฉด ํด๋ผ์ด์ธํธ ์ฌ์ด๋๋ก ๋ผ์ฐํ ํด์ค๋ค.- ๋์ ๋ผ์ฐํ
: ํ์ผ๋ช
์์
_
๋ฅผ ๋ถ์ฌ์ค๋ค. - params ์ํ๋ฑ๋ก :
asyncData({ params }) {}
- validation :
validate({ params }) {}
<script>
์์export default {}
๋ด๋ถ์์ ์ธ์คํด์ค ์ต์ ์ ์ ์ด์ค ์ ์๋ค.
- lifecycle hook (
created
,mounted
) : ์ธ์คํด์ค ์์ฑ๋ถํฐ ์๋ฉธ ์์ ๊น์ง์ ๋ผ์ดํ์ฌ์ดํด - data : ์ปดํฌ๋ํธ ๋ด๋ถ ์ํ
- watch : ์ํ์ ๋ณํ๋ฅผ ๊ฐ์ง
- methods : ์ธ์คํด์ค ๋ด๋ถ ๋ฉ์๋
- props : ๋ถ๋ชจ์๊ฒ์ ๋์ด์จ props
- dom์ ์กฐ์ํ ๋,
this.$refs
๋ก ์กฐ์๊ฐ๋ฅํ๋ค.
- perspective : z์ถ์ ๋ฐ๋ผ view์ ๊ด์ฐฐ์์ ๊ฑฐ๋ฆฌ(๊น์ด๊ฐ)์ ๋ํ๋ (ํฝ์ ๊ธฐ๋ฐ)
- ๊ด์ฐฐ์ ์์ 3d๋ก ์ค์ :
transform-style: preserve-3d;
- perspective ๋ฅผ ๋ถ๋ชจ์ ์ค์ ํ๋๋ ๊ฐ๋ณ ์์์ ์ค์ ํ๋๋์ ๋ฐ๋ผ์ ๋ค๋ฅธ 3d ํจ๊ณผ๋ฅผ ์ค ์ ์์.
- 3d carousel์ wrapper์ธ .image-container์ perspective๋ฅผ ์ค์ ํ๊ณ , .carousel์ 3d ์์ฑ์ ์ฃผ์๋ค. ๊ทธ๋ฆฌ๊ณ .carousel > .image-button์ Yํ์ ๊ฐ(๊ฐ๋์ ๋ฐ๋ผ ์ผ์ ํ๊ฒ ํ์ )๊ณผ Zํ์ ๊ฐ(๋ถ๋ชจ carousel๋ถํฐ์ ๊ฑฐ๋ฆฌ)๋ฅผ ์ฃผ์๋ค.
.image-container {
perspective: 1000px;
}
.carousel {
// ์ด๋ฏธ์ง๋ค์ ํฌ๊ฒ ๋ณด๊ธฐ์ํจ!
transform: translateZ(900px);
// carousel ์์ฒด ํ์
transform: rotateY(${angle}deg)
transform-style: preserve-3d;
}
.image-button {
// rotateY : ์ด๋ฏธ์ง ๋ง๋ค์ ํ์ ๊ฐ
// rotateZ : ๋ถ๋ชจ์ธ carousel์์์ ๊ฑฐ๋ฆฌ
transform: rotateY(${rotateDeg}deg) translateZ(288px);
}
::-webkit-scrollbar {
width: 8px;
}
/* Track */
::-webkit-scrollbar-track {
border-radius: 4px;
}
/* Handle */
::-webkit-scrollbar-thumb {
background: #ffffff88;
border-radius: 4px;
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
background: white;
}
- ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ๋ผ์ฐํ
์ ํ๋ฉด์, ํน์ ์ปดํฌ๋ํธ๋ง ๋ฆฌ๋ ๋๋งํ๊ณ ์ถ์๋ฐ, ๋ผ์ฐํ
์ด ๋๋ฉด nuxt์
page
๊ฐ ๋ชจ๋ ๋ ๋๋ง ๋์๋ค. <NuxtChild>
๋ฅผ ์จ์ ํด๊ฒฐ- pages ๋๋ ํ ๋ฆฌ ๋ด๋ถ์์ index ๋๋ ํ ๋ฆฌ๋ฅผ ๋ง๋ค๊ณ , ๋์ ๋ผ์ฐํ ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ฐ๋ก ์ ์ด์ฃผ๋๊น ๋ผ์ฐํ ๋์ด๋ child์์ ์๋ vue๋ง ๋ ๋๋ง ๋๊ณ ๋๋จธ์ง๋ ๊ทธ๋๋ก ์์๋ค. ์ด๋ค ๋ฐฉ์์ธ์ง๋ ์ดํดํ๋๋ฐ ์์ง ์ต์ํ์ง ์์ ๊ฒ ๊ฐ๋ค.
- ์ฐธ๊ณ ํ ์ฌ์ดํธ : https://ednsquare.com/story/nested-routes-in-nuxt-js-with-example------ayGs0r
- ์ด๋ฏธ์ง๋ฅผ ์ผ๋ถ๋ฌ ๊ณ ํด์๋๋ฅผ ์ผ๋๋ฐ, ์ด๋ฏธ์ง๋ก๋ฉ์, ๊น๋นก๊ฑฐ๋ฆผ์ด ์๋ค. ์ด๋ฏธ์ง ์ด๊ธฐ๋ก๋ฉ ํ์๋ ์บ์ฑ์ด ๋์ ๋ํ๊ธด ํ๋๋ฐ ์๋ฒฝํ ๊น๋นก๊ฑฐ๋ฆผ์ ์์จ ์ ์๋ ๋ฐฉ๋ฒ์ด ์์๊น?
const bgImg = new Image();
bgImg.onload = () => {
this.$refs.imageButton.style.backgroundImage = "url(" + bgImg.src + ")";
};
bgImg.src = this.src;
์ด ๋ฐฉ๋ฒ๋ ์๋ํด๋ดค๋๋ฐ ๊น๋นก๊ฑฐ๋ฆผ์ด ๋จ์์๋ค.
- https://kr.vuejs.org/v2/guide/index.html
- https://ko.nuxtjs.org/
- https://ednsquare.com/story/nested-routes-in-nuxt-js-with-example------ayGs0r
- https://3dtransforms.desandro.com/carousel?fbclid=IwAR04gTvdmnZjMh_psYCenG7NemOpU66HsYSBBoNmIhVutZJic_Ilf4kYnkk
- https://wall.alphacoders.com/
- https://www.flaticon.com/