Porfolio 제작기 - 메인 타이틀 타자기 효과, 팝업창 만들기 via Javascript

김현재·2021년 7월 19일
2
post-thumbnail

Javascript 구현해야지..구현해야지..생각만 하다 드디어 구현했다.

저번주에 구현해 낸 것은 아래와 같다.
1. 메인 타이틀 타자기 효과
2. 타이틀 온로드 되면 아래에서 위로 글자 올라오게 하기
3. mouseover시 이미지 줌 인
4. work 페이지에 "자세히 알아보기" 팝업창

우선, Preview 부터 보고 갑시다.

Preview


구경가볼까..?



구현 내용 자세히 뜯어보기

1. 메인 타이틀 타자기 효과

1. Javascript로 글자가 1개씩 늘어나게 하기

let mainTitle = document.getElementById("main-title");
const content = "Glad to Meet You."
let index = 0;;

// content의 글자가 하나씩 늘어나게 - index로
function typing() {
    let text = `${content[index++]}`;
    if (index <= content.length) {
        mainTitle.textContent += text;
    }   
}

function start(){
    setInterval(typing, 100);
}

알파벳 하나 하나를 index 숫자가 늘어남에 따라 메인 페이지에 추가되도록 했다.
if문을 사용하여 문구 길이를 초과할 때까지 글자가 하나씩 늘어나도록 했고, 딱 1회만 움직이도록 하기 위해 index가 문구 길이에 도달하면 다른 action을 취하지 않도록 뒀다.

글자는 100ms마다 1글자씩 늘어나도록 하기 위해 setInterval함수를 사용하여 천천히 추가되도록 하였다.

2. CSS로 커서 효과 주기

#main-title::after {
    content: "";
    position: absolute; /*main-title따라 움직이도록*/
    width: 1px;
    height: 80%;
    border-right: 8px solid #4834d4;
    animation : blink 0.5s infinite ease;
    
}

@keyframes blink { /* after에 애니메이션 effect */
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

css의 가상 클래스인 :after를 사용하여 글자 뒤마다 자판 위치를 나타내는 바를 만들어주었다.
:after를 사용해서 글자가 늘어날때마다 자동적으로 맨 끝에 붙게 된다.
또한 애니메이션을 사용하여 깜빡깜빡하는(?) 효과를 주었다(정확히 뭐라고 지칭하는지를 모르겠다..커서가 깜빡깜빡하는 상태...ㅠㅠ).



2. 메인 타이틀 onload 되면 아래에서 위로 글자 올라오게 하기

CSS

.main-letter {
    position: relative;
    top: -40%;
    left: 20%;
    opacity: 0;
    transition: all 700ms ease-in-out;
}

.letter-up {
    top: -60%;
    opacity: 1;
}

Javascript

window.onload = function() {
    mainLetter.classList.add("letter-up");
}

letter-up이라는 클래스를 별도로 만들어 메인 타이틀이 움직일 위치값 및 opacity를 지정해줬다.
main-lettertransition을 주어 부드럽게 위치가 변하도록 했다.

화면이 모두 로딩이 완료된 다음에 타이틀이 움직여주었으면 해서 자바스크립트로 onload를 설정했고, 이후 classListletter-up이 추가되도록 해 움직일 수 있도록 했다.



3. mouseover시 이미지 줌 인

HTML

<div class="work">
                    <div class="work-cover">
                        <a href="./works.html" id="workimg" class="work-img interactive"></a>
                    </div>                    
                    <a href="./works.html">interactive web practice</a>
                </div>

CSS

.work-cover { /* cover씌워서 css로 이미지 scale 처리 */
    width: 370px;
    height: 230px;
    overflow: hidden;
    background-color: #000;
}

.work-img {
    display: block;
    width: 100%;
    height: 100%;
    transition: all 400ms ease-out;
}

.work-img:hover {
    transform: scale(1.15);
    opacity: 0.7;
}

work-img를 감싸도록 work-cover를 생성하여 scale처리가 가능하도록 했다.
work-cover에 원하는 이미지 사이즈를 주고, work-imgwork-cover의 사이즈를 따라가도록 가로, 세로를 모두 100%로 주었다.
work-cover의 bgc를 black으로 처리하여 work-imgopacity가 발생하면 화면이 어두워지도록 처리했다.
역시 부드럽게 움직이도록 transition을 주었다.



4. work 페이지에 "자세히 알아보기" 팝업창


"자세히 알아보기"를 클릭하면 팝업이 뜨게 하고, ❌버튼을 누르면 팝업이 사라질 수 있도록 class가 지워졌다 생겼다 하도록 구현했다.

1. 팝업창 열고닫기

// 팝업창 열기
function openPopup(id){
    let popup = document.getElementById(`${id}`);
    popup.classList.remove("disappear");
}

// 팝업창 닫기
function closePopup(id){
    let popup = document.getElementById(`${id}`);
    popup.classList.add("disappear");
}

HTML에 미리 각 파트마다 id를 부여하여 5개중 특정한 1개가 선택할 수 있도록 하였다.
disappear이라는 class를 더하면 css에서 display: none이 되도록 설정했다.
appear보다 disappear쪽이 css에서 처리할 글자 수가 적기에 보다 심플할 것 같아서 disappear로 진행하기로 선택했다.

2. 열고 닫을 놈의 id를 알아내기

function popupID() {
    interBtn.addEventListener("click", () => {
        clickNum = interBtn.dataset.indexNumber;
        openPopup(clickNum);
    });
}
    
function shutPopup() {
    interExit.addEventListener("click", (event) => {
        shutID = event.target.parentNode.parentNode.parentNode.id;
        closePopup(shutID);
    })
}

팝업창을 닫을 때는 ❌ 버튼을 눌러야만 꺼지도록 만들기 위해 sutPopup()이라는 별도의 함수를 생성하였다.



보완하고 싶은 사항🥲

열고 닫을 놈의 id를 찾아내는 과정을 각각의 버튼을 각각 따로따로 누를 때마다 실행되도록 설정해놨는데, 다 만들고 보니 너무 지저분한것 같다.
id도 있는 마당에 하나의 동작으로 5개를 구분지을 수 있을 것 같은데 이상하게도 공통된 class를 부여하면 맨 위의 div에만 작동된다(다른 곳에는 전혀 반영안됨).
어쩔 수 없이 아래와 같이 무식하게(?) 만들었는데 어떻게 5개의 div를 하나의 class만을 사용해 모두 컨트롤 할 수 있을지 고민해보아야 겠다.

function popupID() {
    interBtn.addEventListener("click", () => {
        clickNum = interBtn.dataset.indexNumber;
        openPopup(clickNum);
    });

    brunchBtn.addEventListener("click", () => {
        clickNum =brunchBtn.dataset.indexNumber;
        openPopup(clickNum);
    });

    carrotBtn.addEventListener("click", () => {
        clickNum = carrotBtn.dataset.indexNumber;
        openPopup(clickNum);
    });

    momentumBtn.addEventListener("click", () => {
        clickNum = momentumBtn.dataset.indexNumber;
        openPopup(clickNum);
    });

    habitBtn.addEventListener("click", () => {
        clickNum = habitBtn.dataset.indexNumber;
        openPopup(clickNum);
    });
}
profile
쉽게만 살아가면 재미없어 빙고!

2개의 댓글

comment-user-thumbnail
2021년 7월 20일

어떻게 구현 하시는지 구경하는 재미👍
항상 많이 배우고 가요✨

1개의 답글