You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/ko/7-bank-project/1-template-route/README.md

16 KiB

은행 앱 만들기 Part 1: 웹 앱에서 HTML 템플릿과 라우트

강의 전 퀴즈

강의 전 퀴즈

소개

브라우저에서 JavaScript가 등장한 이후, 웹사이트는 그 어느 때보다도 더 상호작용적이고 복잡해졌습니다. 웹 기술은 이제 브라우저에서 직접 실행되는 완전한 기능의 애플리케이션, 즉 웹 애플리케이션을 만드는 데 일반적으로 사용됩니다. 웹 앱은 매우 상호작용적이기 때문에, 사용자는 작업이 수행될 때마다 전체 페이지를 새로 고치는 것을 원하지 않습니다. 그래서 JavaScript는 DOM을 사용하여 HTML을 직접 업데이트하여 더 부드러운 사용자 경험을 제공합니다.

이번 강의에서는 HTML 템플릿을 사용하여 전체 HTML 페이지를 새로 고치지 않고도 여러 화면을 표시하고 업데이트할 수 있는 은행 웹 앱을 만드는 기초를 다질 것입니다.

사전 요구 사항

이번 강의에서 만들 웹 앱을 테스트하려면 로컬 웹 서버가 필요합니다. 로컬 웹 서버가 없다면 Node.js를 설치하고 프로젝트 폴더에서 npx lite-server 명령을 사용할 수 있습니다. 이 명령은 로컬 웹 서버를 생성하고 브라우저에서 앱을 열어줍니다.

준비

컴퓨터에 bank라는 폴더를 만들고 그 안에 index.html이라는 파일을 생성하세요. 아래의 HTML 보일러플레이트로 시작합니다:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Bank App</title>
  </head>
  <body>
    <!-- This is where you'll work -->
  </body>
</html>

HTML 템플릿

웹 페이지에 여러 화면을 만들고 싶다면, 화면마다 HTML 파일을 하나씩 만드는 방법이 있습니다. 하지만 이 방법에는 몇 가지 불편함이 있습니다:

  • 화면을 전환할 때마다 전체 HTML을 새로 고쳐야 하므로 느릴 수 있습니다.
  • 서로 다른 화면 간에 데이터를 공유하기 어렵습니다.

다른 접근 방식은 HTML 파일을 하나만 사용하고 <template> 요소를 사용하여 여러 HTML 템플릿을 정의하는 것입니다. 템플릿은 브라우저에서 표시되지 않는 재사용 가능한 HTML 블록이며, JavaScript를 사용하여 런타임에 인스턴스화해야 합니다.

작업

은행 앱을 만들면서 로그인 페이지와 대시보드라는 두 개의 화면을 추가할 것입니다. 먼저, HTML 본문에 앱의 다양한 화면을 인스턴스화하는 데 사용할 자리 표시자 요소를 추가합니다:

<div id="app">Loading...</div>

JavaScript로 나중에 쉽게 찾을 수 있도록 id를 부여합니다.

팁: 이 요소의 내용이 교체될 예정이므로, 앱이 로드되는 동안 표시될 로딩 메시지나 인디케이터를 넣을 수 있습니다.

다음으로, 로그인 페이지를 위한 HTML 템플릿을 추가합니다. 여기에는 제목과 탐색을 수행하는 링크가 포함된 섹션만 추가합니다.

<template id="login">
  <h1>Bank App</h1>
  <section>
    <a href="/dashboard">Login</a>
  </section>
</template>

그런 다음, 대시보드 페이지를 위한 HTML 템플릿을 추가합니다. 이 페이지는 다음과 같은 섹션들로 구성됩니다:

  • 제목과 로그아웃 링크가 포함된 헤더
  • 은행 계좌의 현재 잔액
  • 테이블에 표시된 거래 내역 목록
<template id="dashboard">
  <header>
    <h1>Bank App</h1>
    <a href="/login">Logout</a>
  </header>
  <section>
    Balance: 100$
  </section>
  <section>
    <h2>Transactions</h2>
    <table>
      <thead>
        <tr>
          <th>Date</th>
          <th>Object</th>
          <th>Amount</th>
        </tr>
      </thead>
      <tbody></tbody>
    </table>
  </section>
</template>

팁: HTML 템플릿을 만들 때, 어떻게 보일지 확인하고 싶다면 <template></template> 줄을 <!-- -->로 감싸 주석 처리할 수 있습니다.

왜 템플릿에 id 속성을 사용하는 것일까요? 클래스 같은 다른 것을 사용할 수도 있을까요?

JavaScript로 템플릿 표시하기

현재 HTML 파일을 브라우저에서 실행하면 Loading...만 표시된 채 멈춰 있는 것을 볼 수 있습니다. 이는 HTML 템플릿을 인스턴스화하고 표시하기 위해 JavaScript 코드를 추가해야 하기 때문입니다.

템플릿을 인스턴스화하는 일반적인 단계는 다음과 같습니다:

  1. DOM에서 템플릿 요소를 검색합니다. 예를 들어 document.getElementById를 사용합니다.
  2. cloneNode를 사용하여 템플릿 요소를 복제합니다.
  3. appendChild를 사용하여 복제된 요소를 DOM의 표시 가능한 요소 아래에 첨부합니다.

템플릿을 DOM에 첨부하기 전에 복제해야 하는 이유는 무엇일까요? 이 단계를 생략하면 어떻게 될까요?

작업

프로젝트 폴더에 app.js라는 새 파일을 만들고, HTML의 <head> 섹션에 이 파일을 가져옵니다:

<script src="app.js" defer></script>

이제 app.js에서 updateRoute라는 새 함수를 만듭니다:

function updateRoute(templateId) {
  const template = document.getElementById(templateId);
  const view = template.content.cloneNode(true);
  const app = document.getElementById('app');
  app.innerHTML = '';
  app.appendChild(view);
}

여기서 우리는 위에서 설명한 3단계를 정확히 수행합니다. templateId를 가진 템플릿을 인스턴스화하고, 복제된 내용을 앱 자리 표시자 안에 넣습니다. 템플릿의 전체 서브트리를 복사하려면 cloneNode(true)를 사용해야 합니다.

이제 이 함수를 템플릿 중 하나와 함께 호출하고 결과를 확인하세요.

updateRoute('login');

이 코드 app.innerHTML = '';의 목적은 무엇일까요? 이 코드가 없으면 어떻게 될까요?

라우트 생성하기

웹 앱에 대해 이야기할 때, 라우팅이란 URL을 표시해야 할 특정 화면에 매핑하는 작업을 의미합니다. 여러 HTML 파일이 있는 웹사이트에서는 파일 경로가 URL에 반영되므로 이 작업이 자동으로 수행됩니다. 예를 들어, 프로젝트 폴더에 다음과 같은 파일이 있다면:

mywebsite/index.html
mywebsite/login.html
mywebsite/admin/index.html

mywebsite를 루트로 하는 웹 서버를 생성하면 URL 매핑은 다음과 같습니다:

https://site.com            --> mywebsite/index.html
https://site.com/login.html --> mywebsite/login.html
https://site.com/admin/     --> mywebsite/admin/index.html

하지만 우리의 웹 앱은 모든 화면을 포함하는 단일 HTML 파일을 사용하고 있으므로 이 기본 동작이 도움이 되지 않습니다. 우리는 이 매핑을 수동으로 생성하고 JavaScript를 사용하여 표시된 템플릿을 업데이트해야 합니다.

작업

URL 경로와 템플릿을 매핑하기 위해 간단한 객체를 사용할 것입니다. 이 객체를 app.js 파일의 맨 위에 추가하세요.

const routes = {
  '/login': { templateId: 'login' },
  '/dashboard': { templateId: 'dashboard' },
};

이제 updateRoute 함수를 약간 수정해 보겠습니다. templateId를 인수로 직접 전달하는 대신, 현재 URL을 먼저 확인한 다음, 매핑 객체를 사용하여 해당 템플릿 ID 값을 가져옵니다. window.location.pathname을 사용하여 URL에서 경로 섹션만 가져올 수 있습니다.

function updateRoute() {
  const path = window.location.pathname;
  const route = routes[path];

  const template = document.getElementById(route.templateId);
  const view = template.content.cloneNode(true);
  const app = document.getElementById('app');
  app.innerHTML = '';
  app.appendChild(view);
}

여기서 선언한 라우트를 해당 템플릿과 매핑했습니다. 브라우저에서 URL을 수동으로 변경하여 제대로 작동하는지 확인해 보세요.

URL에 알 수 없는 경로를 입력하면 어떻게 될까요? 이를 해결하려면 어떻게 해야 할까요?

탐색 추가하기

우리 앱의 다음 단계는 URL을 수동으로 변경하지 않고 페이지 간 탐색할 수 있는 기능을 추가하는 것입니다. 이는 두 가지를 포함합니다:

  1. 현재 URL 업데이트
  2. 새 URL을 기반으로 표시된 템플릿 업데이트

두 번째 부분은 이미 updateRoute 함수로 처리했으므로, 현재 URL을 업데이트하는 방법을 알아내야 합니다.

JavaScript, 특히 history.pushState를 사용해야 합니다. 이 메서드는 HTML을 새로 고치지 않고 URL을 업데이트하고 브라우저 기록에 새 항목을 생성할 수 있습니다.

참고: HTML 앵커 요소 <a href>는 자체적으로 다른 URL로의 하이퍼링크를 생성할 수 있지만, 기본적으로 브라우저가 HTML을 새로 고치게 만듭니다. 라우팅을 사용자 정의 JavaScript로 처리할 때는 클릭 이벤트에서 preventDefault() 함수를 사용하여 이 동작을 방지해야 합니다.

작업

앱에서 탐색에 사용할 새 함수를 만듭니다:

function navigate(path) {
  window.history.pushState({}, path, path);
  updateRoute();
}

이 메서드는 주어진 경로를 기반으로 현재 URL을 먼저 업데이트한 다음 템플릿을 업데이트합니다. window.location.origin 속성은 URL 루트를 반환하여 주어진 경로에서 전체 URL을 재구성할 수 있게 합니다.

이제 이 함수를 사용하여 경로가 정의된 라우트를 찾을 수 없는 경우의 문제를 해결할 수 있습니다. updateRoute 함수를 수정하여 매칭을 찾을 수 없는 경우 기존 라우트 중 하나로 대체합니다.

function updateRoute() {
  const path = window.location.pathname;
  const route = routes[path];

  if (!route) {
    return navigate('/login');
  }

  ...

라우트를 찾을 수 없는 경우, 이제 login 페이지로 리디렉션됩니다.

이제 링크를 클릭했을 때 URL을 가져오고 브라우저의 기본 링크 동작을 방지하는 함수를 만듭니다:

function onLinkClick(event) {
  event.preventDefault();
  navigate(event.target.href);
}

탐색 시스템을 완성하기 위해 HTML의 로그인로그아웃 링크에 바인딩을 추가합니다.

<a href="/dashboard" onclick="onLinkClick(event)">Login</a>
...
<a href="/login" onclick="onLinkClick(event)">Logout</a>

위의 event 객체는 click 이벤트를 캡처하고 이를 onLinkClick 함수에 전달합니다.

onclick 속성을 사용하여 click 이벤트를 JavaScript 코드에 바인딩합니다. 여기서는 navigate() 함수를 호출합니다.

이 링크를 클릭해 보세요. 이제 앱의 다양한 화면 간에 탐색할 수 있어야 합니다.

history.pushState 메서드는 HTML5 표준의 일부이며 모든 최신 브라우저에 구현되어 있습니다. 오래된 브라우저용 웹 앱을 빌드하는 경우, 이 API 대신 사용할 수 있는 트릭이 있습니다: 경로 앞에 해시(#)를 사용하여 정규 앵커 탐색과 함께 작동하며 페이지를 새로 고치지 않는 라우팅을 구현할 수 있습니다. 이는 원래 페이지 내 내부 링크를 생성하기 위한 목적이었습니다.

브라우저의 뒤로 및 앞으로 버튼 처리하기

history.pushState를 사용하면 브라우저의 탐색 기록에 새 항목이 생성됩니다. 브라우저의 뒤로 가기 버튼을 길게 누르면 다음과 같은 화면이 표시될 것입니다:

탐색 기록 스크린샷

뒤로 가기 버튼을 몇 번 클릭하면 현재 URL이 변경되고 기록이 업데이트되지만, 동일한 템플릿이 계속 표시됩니다.

이는 애플리케이션이 기록이 변경될 때마다 updateRoute()를 호출해야 한다는 것을 알지 못하기 때문입니다. history.pushState 문서를 살펴보면, 상태가 변경되면 - 즉, 다른 URL로 이동하면 - popstate 이벤트가 트리거된다는 것을 알 수 있습니다. 이를 사용하여 문제를 해결할 것입니다.

작업

브라우저 기록이 변경될 때 표시된 템플릿이 업데이트되도록 하기 위해, updateRoute()를 호출하는 새 함수를 연결합니다. 이를 app.js 파일의 맨 아래에 추가합니다:

window.onpopstate = () => updateRoute();
updateRoute();

참고: 여기서는 간결함을 위해 화살표 함수를 사용하여 popstate 이벤트 핸들러를 선언했지만, 일반 함수도 동일하게 작동합니다.

화살표 함수에 대한 복습 영상은 다음과 같습니다:

화살표 함수

🎥 위 이미지를 클릭하면 화살표 함수에 대한 영상을 볼 수 있습니다.

이제 브라우저의 뒤로 및 앞으로 버튼을 사용해 보고, 표시된 라우트가 이번에는 올바르게 업데이트되는지 확인하세요.


🚀 도전 과제

이 앱의 크레딧을 표시하는 세 번째 페이지를 위한 새 템플릿과 라우트를 추가하세요.

강의 후 퀴즈

강의 후 퀴즈

복습 및 자기 학습

라우팅은 웹 개발에서 놀랍도록 까다로운 부분 중 하나이며, 특히 웹이 페이지 새로 고침 동작에서 단일 페이지 애플리케이션(SPA) 새로 고침으로 이동함에 따라 더욱 그렇습니다. Azure Static Web App 서비스가 라우팅을 처리하는 방법에 대해 읽어보세요. 해당 문서에서 설명된 몇 가지 결정이 왜 필요한지 설명할 수 있나요?

과제

라우팅 개선하기


면책 조항:
이 문서는 AI 번역 서비스 Co-op Translator를 사용하여 번역되었습니다. 정확성을 위해 최선을 다하고 있으나, 자동 번역에는 오류나 부정확성이 포함될 수 있습니다. 원본 문서를 해당 언어로 작성된 상태에서 권위 있는 자료로 간주해야 합니다. 중요한 정보의 경우, 전문적인 인간 번역을 권장합니다. 이 번역 사용으로 인해 발생하는 오해나 잘못된 해석에 대해 당사는 책임을 지지 않습니다.