티스토리 뷰

 

 

참고 : 프로그래머스 공식 블로그 

https://prgms.tistory.com/113

 

'2021 Dev-Matching: 웹 프론트엔드 개발자(하반기)' 기출 문제 해설

프로그래머스에서는 지난 2021년 9월 4일 '2021 Dev-Matching: 프론트엔드 개발자(하반기)'의 과제 테스트가 진행되었습니다. 과제 리뷰가 제공되지 않지만, 어떻게 하면 구현을 더 잘할 수 있었을까?

prgms.tistory.com

 

 

 

 


리액트 라우터 동작처럼 바닐라 JS 에서도 새로고침 없이 부드럽게 넘어가는 SPA를 만드는 법을 공부했다.

 

 

 

0. 페이지 구조

 

Home 클릭 시 메인화면으로 넘어오고, Sign Up 클릭 시 회원가입 페이지로 넘어간다.

 

 

메인화면

 

 

 

회원가입 화면

 

 

 

 

 

1. 파일 구조

 

 

 

 

 

2. 파일 역할

 

 

 

2-1. Index.js

 

- Index.html - Index.js 연결

- Index.js 에서 App 컴포넌트를 만듦

 

<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="./style.css">
    <title>Main</title>
</head>
<body>
    <div class="app"></div>
    
    <script src="./Index.js" type="module"></script>
</body>
</html>
import App from "./App.js"

const $target = document.querySelector('.app');
const $app = new App({$target});

 

 

 

2-2. App.js

import Header from "./Components/Header.js";
import HomePage from "./Page/HomePage.js";
import SignupPage from "./Page/SignupPage.js";
import { init } from "./Route.js";

export default function App({$target}) {
    this.route = () => {
        const {pathname} = location;
        console.log('init');

        $target.innerHTML = ``;

        const header = new Header({$target})

        if (pathname === "/index.html") {
            const homePage = new HomePage({$target});
        } else if (pathname === "/signup.html") {
            const signupPage = new SignupPage({$target});
        }
    }

    init(this.route);

    window.addEventListener('popstate', this.route());

    this.route();
}

 

 

this.route()

this.route = () => {
    const {pathname} = location;
    console.log('init');

    $target.innerHTML = ``;

    const header = new Header({$target})

    if (pathname === "/index.html") {
        const homePage = new HomePage({$target});
    } else if (pathname === "/signup.html") {
        const signupPage = new SignupPage({$target});
    }
}

 

- #app 내의 innerHTML 을 비워줌으로써 이전 페이지를 지운다.

- location 객체의  pathname 프로퍼티를 가져와 페이지의 url을 체크한다

- 페이지의 이름에 따라 HomePage / SignupPage 컴포넌트를 렌더링한다

 

 

 

 

2-3 Header.js 

 

 

import { routeChange } from "../Route.js";

export default function Header({$target}) {
    this.$element = document.createElement('header');
    this.$element.className = "header";
    $target.appendChild(this.$element);

    this.render = () => {
        this.$element.innerHTML = `
        <div class="left_bar">
           Home
        </div>
        <div class="right_bar">
            Sign Up
        </div>
        `
    }

    this.$element.addEventListener('click', (e) => {
        const $div = e.target.closest('div');

        if($div.className === "left_bar") {
            console.log('move to main page');
            routeChange("/index.html");
        } else if ($div.className === "right_bar") {
            console.log('move to sign up page');
            routeChange("/signup.html");
        }
    })

    this.render();
}

 

 

Header의 eventListener

this.$element.addEventListener('click', (e) => {
    const $div = e.target.closest('div');

    if($div.className === "left_bar") {
        console.log('move to main page');
        routeChange("/index.html");
    } else if ($div.className === "right_bar") {
        console.log('move to sign up page');
        routeChange("/signup.html");
    }
})

 

- click 이벤트 시 클래스명에 따라 다른 url을 넘겨준다.

- routeChange는 Router.js의 url 변경 메소드이다.

 

 

 

 

2-4 Route.js

 

const ROUTER_CHANGE_EVENT = 'ROUTER_CHANGE';

export const init = (routerCallBack) => {
    window.addEventListener(ROUTER_CHANGE_EVENT, () => {routerCallBack()});
}

export const routeChange = (url, params) => {
    history.pushState(null, null, url);
    window.dispatchEvent(new CustomEvent(ROUTER_CHANGE_EVENT), params);
}

 

history.pushState

- 페이지의 이동없이 주소창의 주소를 바꿔준다.

- 브라우저의 세션 스택에 상태를 추가한다.

 

window.dispatchEvent

- ROUTER_CHANGE_EVENT 이벤트를 새로 커스텀해준다.

- window.dispatchEvent를 통해 새로 커스텀한 이벤트를 실행시켜준다.

 

init

- addEventListener를 통해 routeChange 메소드에서 ROUTER_CHANGE_EVENT를 실행시킨 것을 감지한다.

- 이때 매개변수로 받은 콜백함수를 실행시키는데, 여기선 App.js의 this.route()를 연결해준다.

 

 

App.js

// 생략
import { init } from "./Route.js";

export default function App({$target}) {
    // 생략

    init(this.route);
}

 

따라서 

 

1. Header 요소 클릭 시

2. routerChange 메소드에서 url변경, ROUTE_CHANGE_EVENT 이벤트 (강제)실행

3. init 함수에서 이벤트 감지후 this.route() 실행

4. this.route는 현 페이지의 주소에 따라 다시 렌더링

 

 

 

2-5 App.js 의 popState

 

https://developer.mozilla.org/ko/docs/Web/API/Window/popstate_event

 

popstate - Web API | MDN

Window 인터페이스의 popstate 이벤트는 사용자의 세션 기록 탐색으로 인해 현재 활성화된 기록 항목이 바뀔 때 발생합니다. 만약 활성화된 엔트리가 history.pushState() 메서드나 history.replaceState() 메서

developer.mozilla.org

 

뒤로가기 이벤트 처리를 위해 작성해주었다. 

세션기록 항목이 변경될 때 해당 이벤트가 발생된다. 

 

import Header from "./Components/Header.js";
import HomePage from "./Page/HomePage.js";
import SignupPage from "./Page/SignupPage.js";
import { init } from "./Route.js";

export default function App({$target}) {
	// 생략

    window.addEventListener('popstate', this.route());

    this.route();
}

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
글 보관함