티스토리 뷰

2) handlebar를 활용한 템플릿 작업

기본 예제

  • html에 다음과 같이 template코드를 만듭니다.

<script type="myTemplate" id="listTemplate">

           <li>

     <div>게시자 : {{name}}</div>

     <div class="content">{{content}}</div>

     <div>좋아요 개수 : <span> {{like}} </span></div>

     <div class="comment">

       <div>{{comment}}</div>

     </div>

  </li>

</script>

 

  • handlebar를 설치합니다. 구글에서 handlebar cdn을 검색해서 html에 스크립트를 추가합니다.
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.11/handlebars.min.js"></script>

 

  • javascript에서는 replace로 치환하는 방법 말고, 라이브러리를 사용해서 결과를 얻을 수 있습니다.

var template = document.querySelector("#listTemplate").innerText;

var bindTemplate = Handlebars.compile(template);  //bindTemplate은 메서드입니다.

 

  • compile: 함수를 반환하는 함수인데 미리 만들어진 템플릿 문자열을 가져왔다가 자기가 변수로 기억을 해둡니다. 그리고 데이터가 들어오면 바로 작업을 할 수 있게 미리 사전 작업을 하는 겁니다.
    보통 pre-compile 이라고 하며 템플릿 작업을 할 때는 그런 용어를 많이 씁니다.
  • 여기서 bindTemplate은 함수를 반환하는 함수이며 템플릿 문자열을 가져와서 기억을 해두는, 임시로 보관할 수 있는 함수를 만들어줍니다. bindTemplate을 이용해가지고 템플릿 작업을 할 수가 있습니다.

 

  • 이제 스크립트 안에 데이터를 추가합니다.

var data = {

    "id" : 88,

    "name" : "crong",

    "content" : "새로운글을 올렸어요",

    "like" : 5,

    "comment" : "댓글이다"

};

 

  • 불러온 데이터를 템플릿에 바인드시켜 HTML에 넣습니다.

var show = document.querySelector(".show");

show.innerHTML = resultHTML;

 

  • 최종 HTML
<!DOCTYPE html>
<html>
<head>
<style>
  li{ list-style: none;}
  </style>
</head>
<body>
  <h1>template using handlebar</h1>
  <section class="show">
    
  </section>
  <script type="myTemplate" id="listTemplate">
	<li>
      <div>게시자 : {{name}}</div>
      <div class="content">{{content}}</div>
      <div>좋아요 개수 : <span> {{like}} </span></div>
      <div class="comment">
        <div>{{comment}}</div>
      </div>
    </li>
  </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.11/handlebars.min.js"></script>
<script>
var data = {
                "id" : 88,
"name" : "crong",
                "content" : "새로운글을 올렸어요",
                "like" : 5, 
    "comment" : "댓글이다"
};
var template = document.querySelector("#listTemplate").innerText;
//pre-template
var bindTemplate = Handlebars.compile(template);  //bindTemplate은 메서드입니다.
var resultHTML = bindTemplate(data);
var show = document.querySelector(".show");
show.innerHTML = resultHTML;
</script>
</body>
</html>

 

결과 화면

  • 가져온 뒤에 보면 replace 메서드가 완전히 추상화 되어 있습니다.
  • 기존에는 replace를 써서 치환했는데 이젠 handlebars.complie이 알아서 처리합니다. 해당 구분자는 {{ }} 이며, 해당 구분자로 둘러싸인 것들을 모두 파싱합니다.

 

배열이 포함된 데이터의 처리

  • 데이터 형태가 일정하지 않은 경우가 있을 수 있습니다동적으로 변할 수 있는 부분이 있기 때문에 상황에 따라서 구현이 가능한 템플릿 작업을 직접 만들어야 됩니다.
  • 조건이나 반복 이런 문법들이 있으면 좋겠지만 실제로는 존재하지 않습니다. 그래서 템플릿 라이브러리를 쓰면 그런 것들을 쉽게 처리할 수가 있습니다.
  • 예를 들어 comment 1개 이상일 수 있습니다.

var data = {

    "id" : 88,

    "name" : "crong",

    "content" : "새로운글을 올렸어요",

    "like" : 5,

    "comment" : ["댓글이다", "멋진글이네요", "잘봤습니다"]

};

bindTemplate(v);

 

  • 이런 경우는 이렇게 반복문을 넣을 수도 있습니다. handlebar에서는 each를 사용합니다.

<script type="myTemplate" id="listTemplate">

    <li>

        <div>게시자 : {{name}}</div>

        <div class="content">{{content}}</div>

        <div>좋아요 갯수 <span> {{like}} </span></div>

        <div class="comment">

        <h3>댓글목록</h3>

        {{#each comment}}

            <div>{{@index}}번째 댓글 : {{this}}</div>

        {{/each}}

        </div>

    </li>

</script>

 

  • #은 헬퍼 기능이라 그러는데 쉽게 말하면 handlebar syntax입니다. #each 라 표현하면 반복이 일어나게 되어 있습니다. , 토큰(#each)을 기준으로 /each를 만날 때까지 반복이 됩니다.
  • @index는 루프를 돌면서 for문의 i값을 증가시키는 것처럼 접근을 할 수가 있어요자동으로 전달되는 일종의 매개변수입니다. 그걸 @을 써서 한다는 거예요.

 

  • compile 부분은 동일하므로 결과를 화면에서 확인합니다.

참고) datacomment가 배열이 아니면 출력이 되지 않습니다.

 

data자체가 많아진 경우의 처리

그런데, 실제 데이터는 좀 더 많을 것입니다.

var data = [

           {"id" : 88, "name" : "crong", "content" : "새로운글을 올렸어요", "like" : 5, "comment" : ["댓글이다", "잘했어요"]},

           {"id" : 28, "name" : "hary", "content" : "전 오늘도 노래를 불렀어요", "like" : 0, "comment" : ["제발고만..","듣고싶네요 그노래"]},

           {"id" : 23, "name" : "pororo", "content" : "크롱이 항상 말썽을 피워서 행복해~", "like" : 4, "comment" : []},

           {"id" : 5, "name" : "pobi", "content" : "물고기를 한마리도 잡지 못하다니..", "like" : 5, "comment" : ["댓글이다", "멋진글이네요", "잘봤습니다"]}

];

 

  • 이 상태에서 구현하면 배열이기 때문에 처리가 안 되어서 데이터가 나오질 않습니다. 그래서 데이터를 하나하나 따로 처리해줘야 합니다반복적으로 해서 결과를 합치는 게 좋겠습니다.
  • reduce라는 메서드를 사용하면 좋은데 reduce가 계속 누적된 합을 약간 리커시브하게 동작하는 것처럼 보이는데 누적된 합을 계산할 때 좀 유용합니다.
  • 반환할 때 해야됩니다. 그래야 루프를 돌면서 그 값을 이전에 리턴한 값이 prev, 이전 값으로 되거든요. return을 해서 prev + bindTemplate 을 쓰면 되겠죠. 루프를 돌면서 prev와 next를 돌면서 계속 합을 쌓게 됩니다.

var resultHTML = data.reduce(function(prev,next) {

  return prev + bindTemplate(next);

}, "");

li{

list-style: none;

padding: 3%;

border-top: 1px solid gray;

}

 

구현 화면

 

조건 상황에 따른 처리

  • 예제에서 댓글이 없는 경우에 다른 메시지를 처리해야 한다면 어떨까요template은 말 그대로 고정되어 있는 것이죠.
  • 템플릿 라이브러리인 handlebar에서는 분기, 반복과 같은 방식을 기본으로 지원합니다.
  • #each와 마찬가지로 예약어인 #키워드, #if를 써서 값이 없을 때의 처리를 해줍니다.

<script type="myTemplate" id="listTemplate">

    <li>

        <div>게시자 : {{name}}</div>

        <div class="content">{{content}}</div>

        <div>좋아요 갯수 <span> {{like}} </span></div>

        <div class="comment">

        <h3>댓글목록</h3>

        {{#if comment}}

            {{#each comment}}

                <div>{{@index}}번째 댓글 : {{this}}</div>

            {{/each}}

        {{else}}

            <div>댓글이 아직 없군요</div>

        {{/if}}

        </div>

    </li>

</script>

 

구현 화면

 

참고

  • 좀 더 다양한 상황을 처리해야 한다면, help function을 통해서 처리할 수도 있습니다.
  • 사용자가 직접 커스텀 펑션을 만들고 거기다가 정의해두면 라이브러리가 그 함수를 통해서 적절한 파싱을 진행해 줍니다.
  • 좋아요 갯수가 5개 이상이면 "축하해요. 좋아요가 5개이상 입니다"라는 문자열을 추가해보겠습니다.
  • 먼저 template을 살펴보면 다음과 같습니다likes라는 커스텀 항목을 추가했어요.

<script type="myTemplate" id="listTemplate">

    <li>

        <div>게시자 : {{name}}</div>

        <div class="content">{{content}}</div>

 

        {{#likes like}}

            {{like}}

        {{/likes}}

 

        <div class="comment">

        <h3>댓글목록</h3>

        {{#if comment}}

            {{#each comment}}

                <div>{{@index}}번째 댓글 : {{this}}</div>

            {{/each}}

        {{else}}

            <div>댓글이 아직 없군요</div>

        {{/if}}

        </div>

    </li>

</script>

 

  • 이제 다양한 조건을 설정하는 likes helper를 만들 겁니다. handlebarshelper를 등록하는 과정입니다.
  • 코드의 위치는 script안에 적절한 위치에 놓습니다. likes가 키값이 되고 내부의 함수가 value가 됩니다. 그래서 #likes로 호출하면 value의 함수를 호출할 수 있도록 도와주는 것입니다.

Handlebars.registerHelper("likes", function (like) {

    if (like > 4) {

        return "<span>축하해요 좋아요가 " + like + "개 이상입니다!</span>";

    } else if (like < 1) {

        return "아직 아무도 좋아하지 않아요..";

    } else {

        return like + "개의 좋아요가 있네요";

    }

});

 

  • Helper 함수는 템플릿 처리를 좀 더 유연하게 처리할 수 있게 도와줍니다그 사용법이 막강한 만큼 나중에 잘 활용하면 좋습니다.

 

최종코드

<!DOCTYPE html>
<html>
<head>
<style>
li{
list-style: none;
    padding: 3%;
border-top: 1px solid gray;
  }
  </style>
</head>
<body>
  <h1>template using handlebar</h1>
  <section class="show">
</section>
<script type="myTemplate" id="listTemplate">
    <li>
        <div>게시자 : {{name}}</div>
        <div class="content">{{content}}</div>
        {{#likes like}}
            {{like}}
        {{/likes}}
        <div class="comment">
        <h3>댓글목록</h3>
        {{#if comment}}
            {{#each comment}}
                <div>{{@index}}번째 댓글 : {{this}}</div>
            {{/each}}
        {{else}}
            <div>댓글이 아직 없군요</div>
        {{/if}}
        </div>
    </li>
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.11/handlebars.min.js"></script>
<script>
var data = [
	{"id" : 88, "name" : "crong", "content" : "새로운글을 올렸어요", "like" : 5, "comment" : ["댓글이다", "잘했어요"]},
	{"id" : 28, "name" : "hary", "content" : "전 오늘도 노래를 불렀어요", "like" : 0, "comment" : ["제발고만..","듣고싶네요 그노래"]},
	{"id" : 23, "name" : "pororo", "content" : "크롱이 항상 말썽을 피워서 행복해~", "like" : 4, "comment" : []},
	{"id" : 5, "name" : "pobi", "content" : "물고기를 한마리도 잡지 못하다니..", "like" : 5, "comment" : ["댓글이다", "멋진글이네요", "잘봤습니다"]}
];
Handlebars.registerHelper("likes", function (like) {
    if (like > 4) {
        return "<span>축하해요 좋아요가 " + like + "개 이상입니다!</span>";
    } else if (like < 1) {
        return "아직 아무도 좋아하지 않아요..";
    } else {
        return like + "개의 좋아요가 있네요";
    }
});
var template = document.querySelector("#listTemplate").innerText;
//pre-template
var bindTemplate = Handlebars.compile(template);  //bindTemplate은 메서드입니다.
var resultHTML = data.reduce(function(prev,next) {
  return prev + bindTemplate(next);
}, "");
var show = document.querySelector(".show");
show.innerHTML = resultHTML;
</script>
</body>
</html>

 

생각해보기

  • Handlerbar이외 클라이언트에서 자주 사용되는 template라이브러리는 무엇인가요?
  • ES2015에서 나오는 template literal에서 제공하는 tagged template Literals는 무엇이고 어떻게 사용하나요?

참고자료

[참고링크] handlebar라이브러리의 built-in helper
http://handlebarsjs.com/builtin_helpers.html

 

 

 

Comments