수월한 IT

<template/>를 사용한 동적 페이지 만들기 본문

BOOKS/수월한 자바스크립트

<template/>를 사용한 동적 페이지 만들기

IT여행자 2025. 3. 22. 21:31
728x90

안녕하세요 IT 여행자입니다.

 

이번 여행지는 html5의 <template/> 태그를 사용하여 동적 페이지를 만들어 보는 여행을 해 볼까 합니다. 여행 코스는 4개의 코스로 이루어져 있습니다.

 

 

 

1코스 : 먼저 <template/>를 사용하기 전 공통 html, css를 만듭니다.

2코스 : 동일한 Document에 있는 <template/>를 가져와 동적 페이지를 만들어 봅니다.

3코스 : 외부 파일에 있는 <template/>를 가져와 현재 페이지에서 동적 페이지를 만듭니다.

4코스 : 빈번하게 사용되는 <template/>를 localStorage에 저장하여 cache역할을 하도록 하고 이를 활용해 봅니다.

 

준비물

  • 개발툴 : Visual Studio Code 와 Live Server Extension

Live Server Extension은 VSC의 확장 프로그램에서 검색하여 설치하시면 됩니다.

 

여행을 통한 경험치

  • <template/>의 여러가지 사용법
  • fetch().then() 사용법
  • localStorage 사용법

 

관련 동영상과 전체 코드는 아래의 주소에 있습니다. 참고해 주시기 바랍니다.

전체 코드 : https://github.com/hiparkwg/cache-template.git

관련 영상 :  https://youtu.be/sK3FrWcJ5KQ


파일 구조

 

적당한 폴더를 만들고 VSC를 실행한 후 외쪽 그림과 같이 폴더와 파일을 작성해 두고 시작하겠습니다. 전체 코드는 깃을 참고해 주시기 바랍니다.

 

 

 

 

 

 

- use-template.html, external-template.html, cache-template.html은 같은 코드입니다. 사용할 자바스크립트 코드만이 바뀌었습니다. 각 코스별 코드의 독립성을 유지하기 위해 별도로 만들었을 뿐입니다.

 


1코스

<template/>를 사용하기전 필요한 html과 css를 작성합니다. css는 최소한의 레이아웃만 갖도록 간단히 작성되었습니다.

 

[use-template.html]

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>use template</title>
    <link rel="stylesheet" href="/css/template.css">
</head>
<body>
    <main id="main">
        <h2>Use Template</h2>
        <div id="title">
            <span class="name">Name</span>
            <span class="address">Address</span>
            <span class="email">Email</span>
        </div>
        <div id="template_body"> <!-- (1) -->
            <div class="list">
                <span class="name">홍길동</span>
                <span class="address">서울</span>
                <span class="email">hong@</span>
            </div>
            <div class="list">
                <span class="name">김씨</span>
                <span class="address">부산</span>
                <span class="email">kim@</span>
            </div>
            <div class="list">
                <span class="name">이씨</span>
                <span class="address">대구</span>
                <span class="email">lee@</span>
            </div>
        </div>
    </main>
</body>
</html>

 

(1) id = "template-body" 안에 있는 자식 노드들이 3개가 동일한 구조로 반복되고 있습니다. 이 부분을 <template/>로 만들어 반복처리 하게 됩니다.

 

[template.css]

css부분은 웹페이지가 민망하지 않을 정도로만 작성해 두었습니다.

*{
    box-sizing: border-box;
}
#main{
    width: 600px;
    border : 5px solid #99f;
    padding:20px;
    border-radius: 10px;
}
#main h2{
    text-align: center;
}
#main>#title{
    background-color: #444;
    color : #fff;
}
#main>#title, #main .list{
    display: flex;
}

#main .list:hover{
    background-color: #ccc;
    cursor: pointer;
}
#main .name{ width: 120px;}
#main .address{ width: 150px;}

 

실행 결과는 아래와 같습니다.

 

2코스

기본 페이지가 만들어졌으니 use-templat.html 페이지를 수정하여 아래와 같이 만듭니다.

 

[/html/use-template.html]

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>use template</title>
    <link rel="stylesheet" href="/css/template.css">
    <script defer src="/js/use-template.js"></script> <!-- (1) -->
</head>
<body>
    <main id="main">
        <h2>Use Template</h2>
        <div id="title">
            <span class="name">Name</span>
            <span class="address">Address</span>
            <span class="email">Email</span>
        </div>
        <div id="template_body">
            <template class="template"> <!-- (2) -->
                <div class="list">
                    <span class="name">Name</span>
                    <span class="address">Address</span>
                    <span class="email">Email</span>
                </div>
            </template>
            <!-- (3)
                <div class="list">
                    <span class="name">홍길동</span>
                    <span class="address">서울</span>
                    <span class="email">hong@</span>
                </div>
                <div class="list">
                    <span class="name">김씨</span>
                    <span class="address">부산</span>
                    <span class="email">kim@</span>
                </div>
                <div class="list">
                    <span class="name">이씨</span>
                    <span class="address">대구</span>
                    <span class="email">lee@</span>
                </div>
            -->

        </div>
    </main>
</body>
</html>

 

(1) template 기능을 사용하기 위한 스크립트 파일을 추가합니다.

(2) class="list"와 같은 구조로 <template/> 안에 코드를 작성합니다. <template/> 부분은 웹페이지에 기본적으로 렌더링 되지 않아 화면에 표시되지 않습니다.

(3) 자바스크립트를 통해 지정된 데이터만큼 <div class="list"/>를 만들 예정이기에 이 부분은 삭제합니다.

 

자바스크립트 코드를 살펴보겠습니다.

 

[/js/use-template.js]

( ()=>{
    // template에 표시될 데이터
    let data = [ //(1)
        {'name' : '홍길동', 'address' : '서울', 'email' : 'hong@'},
        {'name' : '김씨',   'address' : '부산', 'email' : 'kim@'},
        {'name' : '이씨',   'address' : '대구', 'email' : 'lee@'},
        {'name' : '박씨',   'address' : '인천', 'email' : 'park@'},
        {'name' : '남씨',   'address' : '강릉', 'email' : 'nam@'},
    ]

    let tempBody = document.querySelector("#template_body"); //(2)
    let template = document.querySelector(".template"); //(3)

    data.forEach( d =>{
        // template clone
        let clone = template.content.cloneNode(true); //(4)
        clone.querySelector(".name").textContent = d.name; //(5)
        clone.querySelector(".address").textContent = d.address;
        clone.querySelector(".email").textContent = d.email;
        tempBody.append(clone); //(6)
    })
})()

 

(1) template에 반복적으로 표시될 데이터입니다. 데이터베이스에서 가져온 자료쯤 생각하셔도 될듯합니다.

(2) template가 추가될 위치를 가져옵니다.

(3) template로 지정된 태그를 가져와 tempate 객체 이름으로 할당합니다.

(4) template 요소를 반복적으로 사용하기 위해 클론을 만듭니다. 매개인자로 true는 template 태그의 하위 요소까지 모두 복사하겠다는 의미입니다.

(5) data.forEach(d=>{...}) 에서 data에 있는 요소 하나를 d로 받았기 때문에 d.name, d.address, d.email 값을 사용하여 clone에 포함된 class명이 .name, .address, .email에 각각 대입합니다.

(6) 만들어진 clone을 template가 추가될 위치에 추가합니다.

 

첫 번째로 만들어진 clone의 모습은 아래와 같을 것입니다.

 

 <div class="list">
      <span class="name">홍길동</span>
      <span class="address">서울</span>
      <span class="email">hong@</span>
</div>

 

 

코드가 정상적으로 실행되었다면 data배열에 있는 자료가 아래의 그림처럼 출력될 것입니다.

 

 


3코스

2코스에서는 사용할 template가 동일한 Document에 있는 것을 사용한 예인데, 이제 외부 파일에 tempate가 존재할 때 이를 가져와 사용하는 방법에 대해 알아보겠습니다. 먼저 external.html 파일을 보겠습니다.

 

[/html/external.html]

<!--외부에 작성된 template-->
<template class="template">
    <div class="list">
        <span class="name">Namasdfasdfe</span>
        <span class="address">Address</span>
        <span class="email">Email</span>
    </div>
</template>

 

use-template.html 파일에 있던 <template/> 영역만 복사한 후 external.html 파일을 만들었습니다. 그럼, external-template.html은 어떤 모습일까요?

 

[/html/external-template.html]

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>external-template</title>
    <link rel="stylesheet" href="/css/template.css">
    <script defer src="/js/external-template.js"></script> <!--(1) -->
</head>
<body>
    <main id="main">
        <h2>external Template 사용하기</h2>
        <div id="title">
            <span class="name">Name</span>
            <span class="address">Address</span>
            <span class="email">Email</span>
        </div>
        <div id="template_body"></div> <!--(2) -->
    </main>    
</body>
</html>

 

(1) 사용할 자바스크립트 파일의 종류만 바뀌었습니다. 

(2) <template/> 영역이 모두 제거되었습니다.

 

그럼 external-template.js 자바스크립트 파일을 살펴보겠습니다.

 

[/js/external-template.js]

( ()=>{
    // template에 표시될 데이터
    let data = [
        {'name' : '홍길동', 'address' : '서울', 'email' : 'hong@'},
        {'name' : '김씨',   'address' : '부산', 'email' : 'kim@'},
        {'name' : '이씨',   'address' : '대구', 'email' : 'lee@'},
        {'name' : '박씨',   'address' : '인천', 'email' : 'park@'},
        {'name' : '남씨',   'address' : '강릉', 'email' : 'nam@'},
    ]

    let templateBody = document.querySelector("#template_body");

    //외부에 정의된 template 문서 읽어오기
    fetch("/html/external.html")  //(1)
    .then(resp=> resp.text()) //(2)
    .then(html=>{ //(3)
        let parser = new DOMParser(); //(4)
        let externalDoc = parser.parseFromString(html, "text/html"); //(5)
        let template = externalDoc.querySelector(".template"); //(6)
        data.forEach( d =>{
            // template clone
            let clone = template.content.cloneNode(true);
            clone.querySelector(".name").textContent = d.name;
            clone.querySelector(".address").textContent = d.address;
            clone.querySelector(".email").textContent = d.email;
            templateBody.append(clone);
        })
    })
})()

 

data 배열의 내용과 template가 들어갈 영역 "#template_body"부분까지는 앞서서 작성된 use-template.js와 동일합니다.

(1) fetch() 함수를 사용하여 외부에 있는 "/html/external.html"파일을 읽어 들입니다.

(2) 파일을 모든 읽은 정보는 resp에 저장되는데 저장된 resp를 모두 문자로 만듭니다.

(3) 문자로 변경된 파일의 내용이 html에 저장되고 변수 html을 사용하여 화살표 함수가 실행됩니다.

(4) 일반적인 문자열로 되어 있는 변수 html을 HTML 태그형태로 바꿔주기 위해 DOMParser() 객체를 생성합니다.

(5) 문자열 변수 html을 HTML 태그 형태로 파싱 하여 externalDoc에 저장합니다.

(6) externalDoc에서 class="template"를 찾아 template에 저장합니다.

 

그 이후로의 작업은 use-template.js에서 작업했던 내용과 동일합니다. 외부에 정의된 template를 가져와 사용할 때 가장 중요한 것은 DOMParser객체를 사용하여 텍스트로 되어 있는 값들을 모두 HTML 형태로 바꿔준다는 것에 있습니다.

실행 결과는 아래와 같습니다.

 

마치 <h2/> 태그의 내용만 바뀐 것처럼 동일합니다.

 


4코스

자 이제 이번 여행 코스의 마지막 코스입니다. template로 분리된 수많은 요소들을 불특정 다수가 빈번하게 사용하고 있다면 서버의 기능이 좋다고 하더라도 서버에 무리를 줄 수 있다는 가정하에 출발합니다. template가 작성되어 있는 파일을 localStorage의 키값으로 사용하여 tempate로 지정된 페이지를 가져옵니다. 즉, localStorage를 일종의 cache 된 영역으로 지정하여 저장된 값을 재 사용할 것입니다.

 

/html/cache-template.html 파일의 내용은 3코스에서 작성된 파일과 동일하되  아래와 같이 자바스크립트를 가져오는 부분만이 다르므로 전체 코드는 생략합니다. 물론에 깃에는 전체 코드가 작성되어 있습니다. 이를 참고해 주시기 바랍니다.

 

<script defer src="/js/cache-template.js"></script> <!--external-template.html과 다른 줄 -->

 

바로 자바스크립트 코드를 살펴보겠습니다.

 

( ()=>{
    // template에 표시될 데이터
    let data = [
        {'name' : '홍길동', 'address' : '서울', 'email' : 'hong@'},
        {'name' : '김씨',   'address' : '부산', 'email' : 'kim@'},
        {'name' : '이씨',   'address' : '대구', 'email' : 'lee@'},
        {'name' : '박씨',   'address' : '인천', 'email' : 'park@'},
        {'name' : '남씨',   'address' : '강릉', 'email' : 'nam@'},
    ]

    let templateBody = document.querySelector("#template_body");

    let url = "/html/external.html"; //(1)
    let saveTemplate = localStorage.getItem(url); //(2)
    if(saveTemplate){
        load(templateBody, saveTemplate); //(3)
    }else{
        fetch(url)
        .then(resp=> resp.text())
        .then(readTemplate=>{
            localStorage.setItem(url, readTemplate); //(4)
            load(templateBody, readTemplate); //(5)
        })
        .catch(err=> console.log("template file not exist error!!!"))
    }
    
    function load(templateBody, cacheTemplate){ //(6)
        let parser = new DOMParser();
        let doc = parser.parseFromString(cacheTemplate, "text/html");
        let template = doc.querySelector(".template");
        data.forEach( d =>{
            // template clone
            let clone = template.content.cloneNode(true);
            clone.querySelector(".name").textContent = d.name;
            clone.querySelector(".address").textContent = d.address;
            clone.querySelector(".email").textContent = d.email;
            templateBody.append(clone);
        })
    }
})()

 

(1) "/html/external.html"을 url로 지정하고 이를 localStorage에 값을 저장하거나 가져올 때 키값으로 사용됩니다.

(2) 페이지가 로딩되면 가장 먼저 url을 키값으로 localStorage에서 값을 가져옵니다.

(3) 만약 localStorage에 url값으로 저장된 자료가 있다면 template가 표시될 위치(templageBody)와 localStorage에서 읽은 saveTemplate를 인자값으로 load() 함수를 호출하여 tempate를 처리합니다.

(4) fetch(url)를 사용하여 관련 HTML 파일을 읽어 문자열로 처리한 후 관련 내용을 localStorage에 저장하여 페이지를 새로 고침 하거나 다음에 다시 페이지가 로딩될 때 서버에서 읽지 않고 바로 클라이언트의 localStorage에서 읽을 수 있도록 조치합니다.

(5) fetch(url)에서 읽은 파일의 정보를 사용하여 load() 함수를 호출합니다.

(6) load() 함수의 두 번째 매개변수인 readTemplate는 localStorage에서 읽은 saveTemplate이거나 fetch(url)에서 읽은 readTemplate 중 하나 일 것입니다. 그 하단에 있는 내용은 external-template.js에서 처리한 내용과 동일합니다.

 

처리 결과는 external-template.html과 같으므로 생략합니다.

 

이것으로 <template/>를 사용하여 동적 HTML 페이지를 만드는 방법과 이를 localStorage에 저장하여 반복적으로 서버에서 읽어 들이는 것이 아니라 각 클라이언트에 저장된 <template/>를 재 사용함으로써 서버에서 처리해야 할 작업을 최소화해 보았습니다.

 

내용이 복잡해 보일 수 있으니 관련 영상도 참고해서 여러분들의 경험치를 끌어 올리시기를 바랍니다.

 

전체 코드 : https://github.com/hiparkwg/cache-template.git

관련 영상 : https://youtu.be/sK3FrWcJ5KQ

 

이것으로 <template/>를 사용한 동적 페이지를 만드는 여행을 마무리 짓겠습니다.

저는 다른 여행지에서 찾아 뵙겠습니다. 감사합니다.