본문 바로가기
Tutorial/port2023

30. 포트폴리오 사이트 만들기 : Vue-Site : 마무리

by @webstoryboy 2023. 7. 31.
Tutorial/portfolio

포트폴리오 사이트 만들기 - Vue

by @webs 2023. 08. 01.
10
포트폴리오 사이트 만들기 : 마무리
난이도 중간

소개

안녕하세요! 웹스토리보이입니다. 뷰 마무리 섹션이 되겠습니다. 벌써 3번째 사이트를 마무리 할 때가 됐네요! 그럼 얼릉 끝내보도록 합시다! 고고 🫤

포트폴리오 사이트 만들기

VITE SITE

  • 1. 셋팅하기
    • 1_1. vite 설치하기
    • 1_2. vite 폴더 정리하기
    • 1_3. gsap/lenis 설치하기
    • 1_4. git 연동하기
  • 2. 레이아웃
    • 2.1 레이아웃 구조 만들기
    • 2.2 메인 레이아웃 구조 만들기
    • 2.3 CSS 셋팅하기
    • 2.4 JavaScript 셋팅하기
  • 3. 헤더 영역
    • 3.1 헤더 구조 잡기
    • 3.2 헤더 디자인 설정
    • 3.3 반응형 작업하기
    • 3.4 메뉴 자바스크립트 설정
  • 4. 인트로 영역
    • 4.1 인트로 구조 잡기
    • 4.2 인트로 디자인 설정
    • 4.3 반응형 작업하기
  • 5. 스킬 영역
    • 5.1 스킬 구조 잡기
    • 5.2 스킬 디자인 설정
    • 5.3 반응형 작업하기
  • 6. 사이트 영역
    • 6.1 사이트 구조 잡기
    • 6.2 사이트 디자인 설정
    • 6.3 반응형 작업하기
  • 7. 포트폴리오 영역
    • 7.1 사이트 구조 잡기
    • 7.2 사이트 디자인 설정
    • 7.3 반응형 작업하기
    • 7.4 스크립트 작업하기
  • 8. 연락처 영역
    • 8.1 연락처 구조 잡기
    • 8.2 연락처 디자인 설정
    • 8.3 반응형 작업하기
  • 9. 푸터 영역
    • 9.1 푸터 구조 잡기
    • 9.2 푸터 디자인 설정
    • 9.3 반응형 작업하기
  • 10. 마무리
    • 10.1 스무스 효과주기
    • 10.2 링크 연결하기
    • 10.3 netlify에 배포하기

REACT SITE

  • 1. 셋팅하기
    • 1_1. React 설치하기
    • 1_2. React 폴더 정리하기
    • 1_3. 라이브러리 설치하기
    • 1_4. git 연동하기
  • 2. 라우팅 및 컴퍼넌트
    • 2_1. 라우팅 설정하기
    • 2_2. 컴퍼넌트 설정하기
    • 2_3. SCSS 설정하기
  • 3. 헤더 영역
    • 3_1. 헤더 구조잡기
    • 3_2. 헤더 디자인 설정
    • 3_3. 헤더 데이터 작업
    • 3_4. 헤더 토글 메뉴 작업하기
  • 4. 인트로 영역
    • 4_1. 인트로 구조잡기
    • 4_2. 인트로 디자인 설정
    • 4_3. 인트로 데이터 작업
  • 5. 스킬 영역
    • 5_1. 스킬 구조잡기
    • 5_2. 스킬 디자인 설정
    • 5_3. 스킬 데이터 작업
  • 6. 사이트 영역
    • 6_1. 사이트 구조잡기
    • 6_2. 사이트 디자인 설정
    • 6_3. 사이트 데이터 작업
  • 7. 포트폴리오 영역
    • 7_1. 포트폴리오 구조잡기
    • 7_2. 포트폴리오 디자인 설정
    • 7_3. 포트폴리오 데이터 작업
  • 8. 연락처 영역
    • 8_1. 연락처 구조잡기
    • 8_2. 연락처 디자인 설정
    • 8_3. 연락처 데이터 작업
  • 9. 푸터 영역
    • 9_1. 푸터 구조잡기
    • 9_2. 푸터 디자인 설정
    • 9_3. 푸터 데이터 작업
  • 10. 마무리
    • 10_1. 데이터 통합하기
    • 10_2. 스무스 효과 넣어주기
    • 10_3. 가로모드 구현하기
    • 10_4. netlify에 배포하기

VUE SITE

  • 1. 셋팅하기
    • 1_1. Vue 설치하기
    • 1_2. Vue 폴더 정리하기
    • 1_3. 라이브러리 설치하기
    • 1_4. git 연동하기
  • 2. 라우팅 및 컴퍼넌트
    • 2_1. 라우팅 설정하기
    • 2_2. 컴퍼넌트 설정하기
    • 2_3. SCSS 설정하기
  • 3. 헤더 영역
    • 3_1. 헤더 구조잡기
    • 3_2. 헤더 디자인 설정
    • 3_3. 헤더 데이터 작업
    • 3_4. 헤더 토글 메뉴 작업하기
  • 4. 인트로 영역
    • 4_1. 인트로 구조잡기
    • 4_2. 인트로 디자인 설정
    • 4_3. 인트로 데이터 작업
  • 5. 스킬 영역
    • 5_1. 스킬 구조잡기
    • 5_2. 스킬 디자인 설정
    • 5_3. 스킬 데이터 작업
  • 6. 사이트 영역
    • 6_1. 사이트 구조잡기
    • 6_2. 사이트 디자인 설정
    • 6_3. 사이트 데이터 작업
  • 7. 포트폴리오 영역
    • 7_1. 포트폴리오 구조잡기
    • 7_2. 포트폴리오 디자인 설정
    • 7_3. 포트폴리오 데이터 작업
  • 8. 연락처 영역
    • 8_1. 연락처 구조잡기
    • 8_2. 연락처 디자인 설정
    • 8_3. 연락처 데이터 작업
  • 9. 푸터 영역
    • 9_1. 푸터 구조잡기
    • 9_2. 푸터 디자인 설정
    • 9_3. 푸터 데이터 작업
  • 10. 마무리
    • 10_1. 스무스 효과 넣어주기
    • 10_2. 가로모드 구현하기
    • 10_3. 링크 클릭 구현하기
    • 10_4. netlify에 배포하기

10. 마무리

10.1 스무스 효과 넣어주기

스무스 효과를 전체를 통괄하는 부분이기 때문에 아무래도 App.vue에 넣는게 좋을 거 같습니다. 다음과 같이 넣어주면 작동하는 것을 확인할 수 있습니다.

<script setup>
import { RouterView } from "vue-router";
</script>

<template>
    <RouterView />
</template>

<script>
import Lenis from "@studio-freight/lenis";

export default {
    mounted: function () {
        this.scrollAnimation();
    },
    methods: {
        scrollAnimation() {
            const lenis = new Lenis({
                duration: 1,
                easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
                direction: "vertical",
                gestureDirection: "vertical",
                smooth: true,
            });

            function raf(time) {
                lenis.raf(time);
                requestAnimationFrame(raf);
            }

            requestAnimationFrame(raf);

            lenis.on("scroll", (e) => {
                console.log(e);
            });
        },
    },
};
</script>

10.2 가로모드 구현하기

포트폴리오 영역에 가로모드를 추가하겠습니다. 해당 컴퍼넌트에 가서 작업을 하겠습니다. template 밑에 다음과 같이 스크립트를 추가하면 됩니다.

<script>
import gsap from "gsap";
import ScrollTrigger from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);

export default {
    mounted: function () {
        this.scrollAnimation();
    },
    methods: {
        scrollAnimation() {
            const horSection = gsap.utils.toArray(".port__item");

            gsap.to(horSection, {
                xPercent: -120 * (horSection.length - 1),
                ease: "none",
                scrollTrigger: {
                    trigger: "#port",
                    start: "top 56px",
                    end: "+=3000",
                    pin: true,
                    scrub: 1,
                    markers: false,
                    invalidateOnRefresh: true,
                    anticipatePin: 1,
                },
            });
        },
    },
};
</script>
  • import gsap from "gsap";: GSAP의 기본 모듈인 gsap을 가져옵니다.
  • import ScrollTrigger from "gsap/ScrollTrigger"; : GSAP의 ScrollTrigger 플러그인을 가져옵니다. ScrollTrigger 플러그인은 스크롤에 따른 애니메이션을 간편하게 구현할 수 있도록 도와줍니다.
  • gsap.registerPlugin(ScrollTrigger); : ScrollTrigger 플러그인을 GSAP에 등록합니다. 이렇게 함으로써 GSAP에서 ScrollTrigger를 사용할 수 있게 됩니다.
  • mounted: Vue 컴포넌트의 라이프사이클 훅 중 하나인 mounted에서 scrollAnimation() 메서드를 호출합니다. mounted 훅은 컴포넌트가 화면에 마운트(렌더링)된 직후에 호출되는 훅입니다.
  • scrollAnimation(): 이 메서드는 스크롤 애니메이션을 설정합니다. gsap.utils.toArray(".port__item")를 사용하여 클래스가 "port__item"인 요소들을 선택하여 배열로 가져옵니다.
  • gsap.to(horSection, {...}): GSAP의 to() 메서드를 사용하여 스크롤 애니메이션을 설정합니다. to() 메서드는 요소의 속성을 특정 값으로 애니메이션화합니다. 여기서는 xPercent 속성을 사용하여 요소들을 수평으로 이동시키는 애니메이션을 설정합니다.
  • scrollTrigger: gsap.to() 메서드의 옵션 객체 내에 scrollTrigger를 설정하여 스크롤 트리거를 사용합니다.
  • trigger: "#port": 스크롤 트리거가 발생하는 요소를 지정합니다. 여기서는 id가 "port"인 요소를 스크롤 트리거로 사용합니다.
  • start: "top 56px": 애니메이션이 시작되는 스크롤 위치를 설정합니다. 여기서는 스크롤 위치가 "top 56px" 지점에서 애니메이션이 시작됩니다.
  • end: "+=3000": 애니메이션이 종료되는 스크롤 위치를 설정합니다. 여기서는 "시작 위치 + 3000px" 지점에서 애니메이션이 종료됩니다.
  • pin: true: 스크롤 트리거가 발생할 때 요소를 고정(pinned)합니다.
  • scrub: 1: 스크롤 시 요소를 얼마나 빠르게 애니메이션화할지를 설정합니다.
  • markers: false: 디버깅용 마커를 표시하지 않도록 설정합니다.
  • invalidateOnRefresh: true: 스크롤 트리거를 새로 고칠 때마다 트리거를 다시 설정합니다.
  • anticipatePin: 1: 고정(pinned)된 요소의 이동을 어느 정도 예상하여 부드러운 스크롤링을 제공합니다.

Vue 컴포넌트의 라이프사이클 훅은 컴포넌트의 생성, 렌더링, 업데이트, 소멸 등의 단계에서 실행되는 일련의 함수들을 말합니다. 이러한 훅들을 활용하여 컴포넌트의 동작을 제어하고 상태를 관리할 수 있습니다. Vue 컴포넌트의 라이프사이클 훅은 아래와 같은 순서로 실행됩니다.

  • beforeCreate: 컴포넌트 인스턴스가 생성되고 초기화되기 전에 실행됩니다. 데이터와 이벤트가 아직 설정되지 않은 상태입니다.
  • created: 컴포넌트 인스턴스가 생성되고 초기화된 후에 실행됩니다. 데이터와 이벤트가 설정된 이후입니다.
  • beforeMount: 컴포넌트 템플릿이 렌더링되기 전에 실행됩니다.
  • mounted: 컴포넌트 템플릿이 렌더링되고 DOM에 마운트된 후에 실행됩니다.
  • beforeUpdate: 컴포넌트 데이터가 변경되어 화면을 다시 그리기 전에 실행됩니다.
  • updated: 컴포넌트 데이터가 변경되어 화면을 다시 그린 후에 실행됩니다.
  • beforeUnmount: 컴포넌트가 언마운트되기 전에 실행됩니다.
  • unmounted: 컴포넌트가 언마운트된 후에 실행됩니다.

10.3 링크 클릭 구현하기

메뉴를 클릭하면 해당 영역으로 이동하는 스크립트를 작업하겠습니다. HeaderSection.vue 에서 작업을 하겠습니다. scrollLink(event)를 추가하고 메서드를 만들겠습니다.

<script setup>
import { headerNav } from "@/constants/index";
</script>

<template>
    <header id="header" role="heading">
        <div class="header__inner">
            <h1 class="header__logo">
                <a href="#">portfolio<em>vue.js</em></a>
            </h1>
            <nav class="header__nav" role="navigation" aria-label="메인 메뉴" :class="{ show: isNavVisible }">
                <ul>
                    <li v-for="(nav, key) in headerNav" :key="key">
                        <a :href="nav.url" @click="scrollLink($event)">{{ nav.title }}</a>
                    </li> 
                </ul> 
            </nav>
            <div
                class="header__nav__mobile"
                id="headerToggle"
                aria-controls="primary-menu"
                :aria-expanded="isNavVisible.toString()"
                @click="toggleMobileMenu"
                >
                <span></span>
            </div>
        </div>
    </header>
</template>

<script>
export default {
    data() {
        return {
            isNavVisible: false,
        };
    },
    methods: {
        toggleMobileMenu() {
            this.isNavVisible = !this.isNavVisible;
        },
        scrollLink(event) {
            event.preventDefault();

            const targetId = event.target.getAttribute("href");
            const targetElement = document.querySelector(targetId);

            if (targetElement) {
                targetElement.scrollIntoView({ behavior: "smooth" });
            }
        },
    },
};
</script>

10.4 netlify에 배포하기

깃헙에 모든 소스를 올리겠습니다.

git add .
git commit -m "🥺 마무리 완료"
git push -u origin main

이제 빌드를 한번해보겠습니다. 지금까지 작업했던 소스는 브라우저가 읽을 수 없습니다. 브라우저가 읽을 수 있도록 컴파일을 해주고 빌드 작업을 해주어야 브라우저에서 볼 수 있습니다. 빌드 과정을 통해 소스는 가벼워지고 효율성이 증가됩니다.

$ npm run build

빌드화 과정을 거치면 소스가 정리된 것을 볼 수 있습니다. CSS파일 JavaScript파일도 여백없이 한줄로 정리된 것을 확인 할 수 있고, 이미지도 이름이 변형되어 정리된 것을 확인할 수 있습니다. 아래와 같은 메세지가 나오면 성공한 것입니다.

webstoryboy@Webstoryboyui-MacBookPro vue-site % npm run build

> vue-site@0.0.0 build
> vite build

vite v4.4.7 building for production...
✓ 60 modules transformed.
dist/assets/arrow-02f0d4f8.svg     0.55 kB │ gzip:  0.30 kB
dist/index.html                    0.65 kB │ gzip:  0.52 kB
dist/assets/port05-a2e9bbc5.jpg   50.16 kB
dist/assets/port04-5b48949a.jpg   65.93 kB
dist/assets/port08-2deb8171.jpg   88.35 kB
dist/assets/port02-d9b065dc.jpg  113.89 kB
dist/assets/port01-0940cbbf.jpg  127.59 kB
dist/assets/port06-124a2860.jpg  145.58 kB
dist/assets/port10-43bb1e1c.jpg  152.40 kB
dist/assets/about-362eae76.jpg   213.50 kB
dist/assets/port07-a5273c1f.jpg  218.56 kB
dist/assets/port09-b7969920.jpg  225.89 kB
dist/assets/port03-438b6d55.jpg  269.35 kB
dist/assets/index-660ce224.css    18.50 kB │ gzip:  3.43 kB
dist/assets/index-d2565f32.js    210.90 kB │ gzip: 83.09 kB
✓ built in 995ms

마지막으로 다시 한번 업로드 해보겠습니다. 이렇게 올려도 깃헙에는 큰 변화가 없을 것입니다. .gitignore파일에 build 폴더가 포함되어 있기 때문에 파일은 올라가지 않습니다.

git add . 
git commit -m "😇 1차 완성본"
git push -u origin main

이제 netlify 사이트로 이동하겠습니다. 로그인을 하고 add new site 버튼을 누르고 import an existing project를 선택하겠습니다.

vue portfolio

deploy width GitHub 버튼을 클릭하고 port2023-vue를 검색 후 선택합니다.

vue portfolio

이번에도 딱히 수정할께 없습니다. 바로 Deploy port2023-vue 버튼을 클릭하면 됩니다. 도메인 변경과 깃헙에 올리는 건 혼자 할 수 있겠죠?

vue portfolio

어바웃 부분과 정리 부분은 꼭 잘 정리해주세요!

vue portfolio

3. 마무리

이렇게 해서 포트폴리오 사이트 만들기 뷰도 다 완성이 되었습니다. 깃헙에 올려서 README.md에 정리도 잘 해주세요! 또 성공하신 분들은 댓글에 주소를 달아주세요! 디자인과 스타일은 자기 스타일로 변경하셔도 됩니다. 수고하셨습니다. 🫠


예제 목록

댓글