Web 관련/HTML

웹 페이지를 동적으로 그리고 부분적으로 포함시키기

iKay 2019. 3. 10. 09:51
반응형

0. 들어가기 전

지난번에 HTML파일을 tag 별로 분리하는 방법을 게재했다. 그러나 각 섹션(section)별로 라우팅(routing)해 본문(article)에 보여주는 작업은 하지 않았다. 오늘은 그 방법을 소개한다. 이것이 적용된 곳은 여기를 참고하면 된다. 

 

1. 섹션별로 라우팅해 본문에 보여주는 작업?

들어가기 전에 '섹션별로 라우팅해 본문에 보여주는 작업'을 하지 않았다고 말했는데 이게 무슨 말인지, 왜 해야하는지 간단히 말하고 시작하려고 한다. 우선 아래 웹 페이지 그림을 보자. 웹 페이지를 만들 때 <nav>속 'section n'을 클릭하면 그 내용이 <article>{ `section n의 내용` }</article>내에 나오게하고 싶다. 다시 말해 <nav>내에 <a>를 달아서 각 section의 제목을 나열하고 <article>내에는 section에 해당되는 html 파일을 클릭이벤트시 동적으로 <article>내에 부분적으로 load하고 싶다.  

 

 

 

 

가장 쉬운 방법은 <header>, <footer>, <nav>가 동일한 웹 페이지를 각 section 수 만큼 만들고 각각 <article>만 다르게 만드는 것이나 이렇게 하면 낭비가 매우 심해지기 때문에 이렇게 하지 않는 것이 좋다.    

 

 

웹 페이지 동적으로 그리고 부분적으로 포함시키기 

 

2. 작업 디렉토리 구조

저번 작업 디렉토리 구조에서 article 본문을 제공할 .html 디렉토리와 파일, 동적으로 웹 페이지를 제공하기 위해 필요한 로직이 들어가는 includeRouter.js 파일을 추가한다. routers라고 명명한 이유는 웹 페이지를 분리해 포함시키는 역할을 하기 때문이다.    

 

public ㅡ ㅡ html ㅡㅡ index.html            

            |            |        ㄴㅡ header.html

            |            |        ㄴㅡ nav.html

            |            |        ㄴㅡ article.html

            |            |        ㄴㅡ footer.html

            |            |

            |            ㄴㅡ acticles ㅡㅡ section1.html

            |                                      ㄴㅡ section2.html

            |                                      ㄴㅡ section3.html

            |                                      ㄴㅡ ...

            |                                      ㄴㅡ sectionN.html

            |  

            ㄴㅡㅡ js ㅡㅡ includeHTML.js

                          ㄴㅡ includeRouter.js

 

이렇게 분리한다면 앞으로 웹 페이지에 어떤 내용을 퍼블리싱하고자 할 때, 이 웹페이지의 구조를 모르는 사람일지라도 <nav>에 section의 제목과 articles 디렉토리에 그 내용만 추가하면 되므도 더욱 편리할 것이다.

 

3. 소스코드

소스 코드를 보자. 지난 번 포스팅에서 수정된 부분, 추가된 부분만 올렸다. 

 

includeRouter.js

function includeRouter(cb) {
  var content, file, xhttp, i;
  document.body.addEventListener("click", e => {
    file = e.target.getAttribute("route-link");
    if (file) {
      content = document.getElementById("content");
      xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function() {
        if (this.readyState == 4) {
          if (this.status == 200) {
            content.innerHTML = this.responseText;
            var scripts = content.getElementsByTagName("script");
            for (var i = 0; i < scripts.length; i++) {
              eval(scripts[i].text);
            }
            setTimeout(function() {
              cb(e);
            }, 0);
          }
          if (this.status == 404) {
            content.innerHTML = "Page not found.";
          }
        }
      };
      xhttp.open("GET", file, true);
      xhttp.send();
    }
  });
}

 

설명을 조금 붙이겠다.

 

문서(document)의 본문(body)에 'click' 이벤트를 등록해, 클릭한 엘리먼트(target) 중 'route-link'라는 속성이 있는 엘리먼트에 대해서만 작업한다. 'route-link'에는 클릭 시 제공될 .html의 위치가 입력된다. 만약 웹 페이지가 지정된 곳에 있다면, 문서에서 content라는 id를 갖는 곳의 내부에 html을 포함시킨다. 포함 되는 순간 <script>도 실행돼야 하기 때문에 eval( )도 반드시 넣어준다. 사실 내가 원했던 것은 html 뿐만 아니라 script도(그리고 css도) 분리하는 것이었기 때문이다. 제공하려는 화면의 html, javascript 그리고 css를 분리시킬 수 있어야 생산성이 높아지지 않겠는가? 그런데 아직 css는 완전히 분리하지 못했다. id나 class 네이밍 규칙을 정해 분리해도 되지만 파일 단위로 분리하는 방법이 필요할 것 같다. 마치 vue.js의 component처럼 말이다. 이것은 추후에 고민해볼 예정이다.      

 

article.html

<div id="content">
  <!-- 각 section에 해당되는 웹 페이지가 load 되는 곳 -->
</div>

 

nav.html

<ul>
  <li>
    <a href="#section1" route-link="/static/html/articles/section1.html">
      section1
    </a>
  </li>
  <li>
    <a href="#section2" route-link="/static/html/articles/section2.html">
      section2
    </a>
  </li>
  <li>
    <a href="#section3" route-link="/static/html/articles/section3.html">
      section3
    </a>
  </li>
</ul>

 

includeRouter.js 부분을 설명하면서 'route-link'의 속성(attribute)에 대해 설명했다. 이 속성에 동적으로 load할 웹 페이지의 위치를 명시한다. 

index.html

<!DOCTYPE html>

<head>
    <meta charset="UTF-8">
    <title>분리된 HTML</title>
    <script src="/static/js/includeHTML.js"></script>
    <script src="/static/js/includeRouter.js"></script>
</head>

<body>
    <header include-html="/static/html/header.html"></header>
    <nav include-html="/static/html/nav.html"></nav>
    <article include-html="/static/html/article.html"></article>
    <footer include-html="/static/html/footer.html"></footer>
</body>
<script>
    includeHTML(function () {
        includeRouter(function () {
            // do something in the future
        });
    });
</script>

</html>

 

지난 번과 달리 includeRouter.js를 index.html에 포함시켰고, includeRouter( )함수도 includHTML( ) 후 실행되도록 했다. 

 

articles/section1.html

 

예제 더미 데이터이다. 

<h2>Section 1</h2>
<div>
    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's
    standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a
    type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting,
    remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing
    Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of
    Lorem Ipsum.
</div>
<script>
    alert('section 1');
</script>

 

4. 동작 확인

아래 그림과 같이 <nav>내에 section1 을 클릭하면 동적으로 .html이 포함되고 또헌 <script>내용도 실행됨을 확인할 수 있다. 

 

 

 

 

 

 

 

 

5. 소스코드

https://github.com/hgs0426/my-html-template

 

6. 마치며

현재 많은 웹 프론트엔트 프레임워크가 유행하고 있고, 그것을 발빠르게 익히는 것도 좋지만 가끔은 이렇게 수고스럽더라도 직접 이런 템플릿을 직접 만들어 보는 것을 시도해 보고 실험해 보는 것도 괜찮을 것 같다.   

반응형