시작하기

VueJS 선언적 렌더링(Declarative Rendering)방식으로 시작하기

지후아빠
12-15 15:55

요약

  1. 선언적 렌더링은 Vue.js를 이용해 프론트엔드를 간단히 구성하는 방법입니다.
  2. 빠른 프로토타입 제작에 유용하며, 학습 및 테스트 환경에서 적합합니다.
  3. H:Dev+ 샘플 코드를 활용하여 직접 구현하고 실행해볼 수 있습니다.

선언적 렌더링(Declarative Rendering)

'선언적 렌더링(Declarative Rendering)'은 HTML에 출력될 요소를 직접 선언하는 방식입니다. Vue.js 공식 문서에서는 아래와 같은 방식을 선언적 렌더링으로 설명하고 있습니다.

JS 예제 코드

import { createApp } from 'vue'
createApp({
    data() {
        return {
            count: 0
        }
    }
}).mount('#app')

Template

<div id="app">
  <button @click="count++">
    Count is: {{ count }}
  </button>
</div>

H:Dev+와 선언적 렌더링

H:Dev+**를 가장 빠르게 경험할 수 있는 방법은 선언적 렌더링 방식을 이용해 프론트엔드를 구현하는 것입니다.

  1. 선언적 렌더링의 활용 대상Vue.js로 프론트엔드 개발을 학습하는 사용자
  2. 빠른 프로토타입을 구현하려는 중소기업 또는 에이전시

주의사항선언적 렌더링 방식은 보안적 위험(예: SECORE_KEY 노출) 및 기능 제한이 있을 수 있으므로 프로덕션 환경에서는 권장되지 않습니다.그러나, 빠른 프로토타입 제작에는 매우 유용합니다.

H:Dev+ 콘솔에서 SECORE_KEY를 재 설정 할 수 있습니다..

샘플 코드

Git Repositorygit clone https://github.com/zmania/HDevPlus-example.git

디렉터리 안내
nuxt3 : nuxt3 기반의 SSR(Server Side Rendering)방식 example
php : php example
spring-boot : sprint boot example (resource/static:VueJS, resource/templates : thymeleaf)
vue-dr : VueJS 3 example(declarative rendering)
vue : VueJS 3 example(Imperative rendering)

vue-dr 디렉터리에는 선언적 렌더링 방식으로 작성된 Vue.js 코드가 포함되어 있습니다.

실행 방법

vue-dr 디렉터리의 index.html 파일을 크롬 또는 엣지 브라우저에서 열면 실제로 H:Dev+와 연동된 페이지를 확인할 수 있습니다.

선언적 렌더링 샘플 코드

HTML 페이지 상단에 데이터를 요청하는 스크립트(영역)를 정의하고, 페이지 내부에서 Vue.js의 데이터 바인딩 기능을 사용하여 데이터를 출력합니다.

<!doctype html>
<html lang="en" data-bs-theme="auto">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
    <meta name="generator" content="Hugo 0.111.3">
    <title>H:Dev+ Sample Code</title>
    <!-- BOOTSTRAP OPTIONAL -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
    <!-- REQUEST DATA -->
    <script>
      const requestData = {
        'dataID': 'GET_POST_LIST',
        'list_per_page': 2,
        'page_link_url': 'list.html',
        'search_keyword': new URLSearchParams(window.location.search).get('search_keyword'),
        'page': new URLSearchParams(window.location.search).get('page') ? new URLSearchParams(window.location.search).get('page') : 1
      };
    </script>
    <style>
      [v-cloak] {
        display: none;
      }
    </style>
  </head>
  <body>
    <div id="app" v-cloak>
      <gnb-comp :output="output"></gnb-comp>
      <div class="container">
        <main>
          <div class="row g-5">
            <div class="col-12">
              <div class="text-center">
                <h2 class="mt-5 mb-3">게시물 목록</h2>
              </div>
              <div class="py-2 d-flex justify-content-between align-items-center">
                <small class="smaller text-black"> Result {{output.pagination.total_result_num}} post / total {{output.total_post_count}} post </small>
                <a :href="output.user.auth_flg ? './add.html' : '../member/login.html'" class="btn btn-sm btn-dark d-flex justify-content-between align-items-center lh-1">
                  <small class="smaller">ADD</small>
                </a>
              </div>
              <div id="post_list" data-load-type="vue-pagination" class="row h-post-list">
                <div class="col-12 my-3" v-if="output.post_list.length>0" v-for="post in output.post_list">
                  <div class="card h-100">
                    <div class="card-body">
                      <div class="d-flex justify-content-between align-items-center">
                        <small>{{post.reg_name}}</small>
                        <small>{{post.create_date}}</small>
                      </div>
                      <hr />
                      <h1 class="fs-3 card-title py-3">
                        <a :href="'./view.html?post_key='+post.post_key" v-html="post.subject"></a>
                      </h1>
                      <p class="card-text" v-html="post.content"></p>
                    </div>
                  </div>
                </div>
                <div class="col-12" v-else>
                  <div class="my-2 d-flex justify-content-center align-items-center alert alert-light">
                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-bell" viewBox="0 0 16 16">
                      <path d="M8 16a2 2 0 0 0 2-2H6a2 2 0 0 0 2 2zM8 1.918l-.797.161A4.002 4.002 0 0 0 4 6c0 .628-.134 2.197-.459 3.742-.16.767-.376 1.566-.663 2.258h10.244c-.287-.692-.502-1.49-.663-2.258C12.134 8.197 12 6.628 12 6a4.002 4.002 0 0 0-3.203-3.92L8 1.917zM14.22 12c.223.447.481.801.78 1H1c.299-.199.557-.553.78-1C2.68 10.2 3 6.88 3 6c0-2.42 1.72-4.44 4.005-4.901a1 1 0 1 1 1.99 0A5.002 5.002 0 0 1 13 6c0 .88.32 4.2 1.22 6z" />
                    </svg>
                    <span class="ms-2">게시물이 없습니다.</span>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </main>
        <bottom :output="output"></bottom>
      </div>
    </div>
    <!-- JQUERY REQUIRED -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.form/4.3.0/jquery.form.min.js"></script>
    <!-- VUE -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.47/vue.global.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/4.1.6/vue-router.global.js"></script>
    <!-- BOOTSTRAP OPTIONAL -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"></script>
    <!-- CONNECTOR -->
    <script src="../_connector/yellow.501.js"></script>
    <script src="../components/gnb.js"></script>
    <script src="../components/bottom.js"></script>
  </body>undefined
</html>

명령형 렌더링(Imperative Rendering)

위에서 작성한 선언적 렌더링 방식은 이후 명령형 렌더링 방식으로 확장해도 활용이 용이합니다. 명령형 렌더링의 예제는 vue 디렉터리에서 확인할 수 있습니다.