본문 바로가기
Font-end/Javascript

[모듈] Prototype을 이용한 모듈 패턴으로 Element 모듈 만들기

by 허도치 2020. 3. 19.
0.서론

 기존의 웹은 페이지가 전환될 때마다 서버에서 화면을 렌더링한 후 브라우저에 바로 그려주는 서버 사이드 렌더링(SSR, Server-Side Rendering) 방식을 주로 사용하였다. 그러나, 페이지가 전환될 때마다 화면 전체를 다시 그리기 때문에 페이지가 로드되는 속도가 느리고 화면이 자주 깜빡거렸다.

 그래서, 최근에는 브라우저에서 XHR을 통해 필요한 데이터만 서버에 요청한 후 데이터를 가지고 브라우저에서 화면을 그려주는 클라이언트 사이드 렌더링(CSR, Client-Side Redering) 방식을 많이 사용하고 있다. CSR은 요소를 생성할 때마다 동적으로 요소들을 생서한다. 그래서, 데이터만 입력받으면 요소를 생성할 수 있도록 필요한 모듈들을 미리 만들어 사용한다. 대표적인 예로 페이스북에서 만든 React 라이브러리가 있다.

 이번 포스트에서는 Prototype을 이용한 모듈 패턴으로 Element를 동적으로 생성하는 모듈을 만들어 보도록 하겠다.

 

 

 

1. 프로젝트 준비
1-1. 프로젝트 구조

1) modules/MyListItem.js
   : 리스트 아이템을 커스터마이징한 모듈.

2) index.html
   : 기본 화면

 

 

 

2. HTML 작성
2-1.index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html>
<html lang="kr">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Prototype을 이용한 모듈 패턴</title>
</head>
<body>
  <div>
    <ul id="list"></ul>
  </div>
  <script src="./modules/MyListItem.js"></script>
  <script type="text/javascript">  
    // 리스트 요소 탐색
    const list = document.getElementById("list");
    
    // 리스트에 10개의 아이템을 추가
    Array(10).fill(1).forEach(function(data, idx){
      const key = data+idx;
 
      // 아이템 요소 생성
      const li = document.createElement("li");
 
      // 아이템에 모듈을 적용
      const instance = li.myListItem({
        id: "item-"+key,
        parent: list
      });
      
      // 리스트에 아이템 추가
      list.appendChild(li);
    });
  </script>
</body>
</html>
cs

1) [ 10 ln ] - 리스트 요소

2) [ 12 ln ] - 리스트 아이템 모듈을 로드

3) [ 18-32 ln ] - 리스트에 아이템 추가
   : [ 25-28 ln ] - 생성한 리스트 아이템 모듈을 <li>태그에 적용.

 

 

 

3. Javascript 작성
3-1. modules/MyListItem.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// 리스트 아이템 Object 생성
const MyListItem = function(config, el){
  const self = this;
  
  // 데이터를 저장할 변수
  let datas = {}
  
  // 현재 요소의 인스턴스를 가져올 수 있도록 설정
  el.instance = self;
  el.getInstance = function(){
    return this.instance;
  }
 
  // Object에 현재 요소를 저장
  self.el = el;
 
  // 기본 함수를 설정
  self.setConfig = function(k, v){ config[k] = v; }
  self.getConfig = function(k){ return config[k]; }
  self.setData = function(k, v){ datas[k] = v; }
  self.getData = function(k){ return datas[k]; }
}
 
// Prototype을 이용한 모듈 패턴
MyListItem.prototype = (function(){
  // 초기화 함수
  function _init(self){
    _initRender(self);
    _initEvent(self);
  }
  
  // 렌더링 함수
  function _initRender(self){
    const id = self.getConfig("id");
    const html = '<a style="color: red;">'+id+'</a>';
    
    self.el.innerHTML = html;
    self.el.id = self.getConfig("id");
  }
  
  // 이벤트 바인딩 함수
  function _initEvent(self){
    const a = self.el.querySelector("a");
    a.addEventListener("click"function(event){
      event.preventDefault();
      
      alert(this.innerText);
    });
  }
 
  // 각 함수를 Prototype에 적용
  return {
    init: function(){
      _init(this);
    },
    setText: function(text){
      const tag = self.el.querySelector("a");
      tag.innerText = text;
    },
    setHTML: function(html){
      this.el.innerHTML = html;
    }
  }
})();
 
// Element 객체에 myListItem 함수를 추가
Element.prototype.myListItem = function(setting){
  // 기본 설정
  const config = {
    id: null,
    parentnull,
    url: null,
    data: null
  }
  
  // 추가 설정
  if( setting ){
    Object.assign(config, setting);
  }
  
  // 현재 요소에 MyListItem 모듈을 적용
  const module = new MyListItem(config, this);
  
  // 초기화
  module.init();
  
  // 인스턴스를 반환
  return module;
}
cs

1) [ 2-22 ln ] - 모듈화할 Object를 생성
   : [ 9-12 ln ] - 모듈이 적용된 Element에서 모듈의 기능을 사용하려면 instance가 필요함.
   : [ 15-21 ln ] - 모듈의 정보를 접근하기 위한 변수 및 함수.

2) [ 25-64 ln ] - Prototype을 통해 Object에 클로저 함수들을 적용
   : [ 27-30 ln ] - 초기화 함수'
   : [ 33-39 ln ] - 렌더링 함수, 현재 요소에 'id'속성과 '<a>'태그를 추가.
   : [ 42-49 ln ] - '<a>'태그에 클릭 이벤트를 적용.

3) [ 52-63 ln ] - 클로저 함수들을 호출하는 함수들을 반환
   : [ 56-59 ln ] - 텍스트를 변경하는 함수.
   : [ 60-62 ln ] - 아이템의 내부 요소를 HTML로 변경.

4) [ 67-89 ln ] - Element 객체에 myListItem 함수를 추가
   : [ 82 ln ] - 옵션(config)과 함수를 호출한 요소(this)를 전달하여 모듈을 생성.
   : [ 85 ln ] - 초기화 함수를 호출하여 Element를 렌더링.

 

 

 

4. 실행
4-1. index.html 실행

1) 실행하면 위와 같이 item-1 ~ item-10 까지 리스트가 추가됨.

2) 아이템을 클릭하면 alert가 실행됨.

 

4-2. 요소에 적용된 모듈 함수 사용

1
2
3
4
5
6
7
8
9
const item4 = document.getElementById("item-4");
const item4_inst = item4.getInstance();
console.log(item4_inst);
item4_inst.setText("아이템4 입니다.");
 
const item7 = document.getElementById("item-7");
const item7_inst = item7.getInstance();
console.log(item7_inst);
item7_inst.setHTML("<h1>아이템7입니다.</h1>");
cs

1) [ 1 ln ] - <li id="item-4">요소를 탐색

2) [ 2 ln ] - <li>태그에 적용된 모듈을 가져오기

3) [ 3 ln ] - 모듈 정보 확인

4) [ 4 ln ] - 모듈의 함수를 사용하여 텍스트를 변경.
   : [ 9 ln ] - innerHTML을 사용하기 때문에 click 이벤트가 실행되지 않음.

 

 

 

마치며

- Prototype을 이용해서 간단하게(?) 모듈 패턴을 만들어 보았다.
- Javascript에 익숙하지 않고 어렵게 느껴진다면, Prototype과 클로저를 먼저 선행학습하는 것을 추천한다.

댓글