Ajax에 대해서(jQuery를 이용한 플리커 API 처리)

AJAX란?

대화식 웹 애플리케이션의 제작을 위해 아래와 같은 조합을 이용하는 웹 개발 기법입니다.
Asynchronous Javascript and XML – 비동기적인 자바스크립트와 XML

  • 표현정보를 위한 HTML과 CSS
  • 동적인 화면 출력 및 표시 정보와의 상호작용을 위한 DOM, 자바스크립트
  • 웹서버와 비동기적으로 데이터 교환하고 조작하기 위한 XML, XSLT, XMLHttpRequest

AJAX의 장점과 단점

장점

  • 페이지 이동이 없이 빠른속도로 화면전환할 수 있다.
  • 서버처리를 기다리지 않고 비동기 요청이 가능하다.
  • 수신하는 데이터 양을 줄일 수 있고, 클라이언트에게 처리를 위임할 수 있다.

단점

  • Ajax를 쓸 수 없는 브라우저에 대한 문제가 있다.
  • 지원하는 캐릭터셋이 한정되어 있다.
  • 디버깅이 용이하지 안다.

웹 브라우저

Ajax 지원

  • MS IE5 이상
  • 오페라 8.0 이상
  • 오페라 모바일 8.0 이상
  • 구글크롬

Ajax 미지원

  • 오페라 7이하
  • MS IE 4.0 이하
  • 텍스트 기반 브라우저 lynx, w3m
  • 시각장애인을 위한 브라우저
  • 1997년 이전 브라우저

활용사례

  • 검색어 자동완성
  • 회원가입폼에서의 아이디 중복 체크
  • 페이스북이나 구글의 알림 서비스(숫자)

크로스 도메인 문제

기본적으로 Ajax 요청은 도메인이 같은 호스트로만 요청이 가능하고, 도메인이 다른 호스트에 요청을 하게 되면 콘텐츠를 받아올 수 없습니다.
예를들어 aaa.com 이라는 호스트에서 http://bbb.com/rss.xml 을 ajax 요청해서 받아 올 수는 없습니다.

이를 해결할 수 있는 4가지 방법이 있습니다.

  • 프록시 방식
  • 호출되어지는 호스트에서 허용하는 헤더를 넣는 방식
  • script 태그를 동적으로 생성하는 방식

플리커 API 활용 예제

예제보기

HTML

1
2
3
<div id="result" style="width:800px;height:60px;overflow-y:auto;border:1px solid #000000;padding:10px;margin:0 auto;margin-bottom:10px;"></div>
<div style="display:none;width:800px;height:20px;margin:0 auto;" id="loading">Loading.</div>
<ul id="list"></ul>

Javascript

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
<script type="text/javascript" src="http://code.jquery.com/jquery-1.5.min.js"></script>
<script>
// 타이머
var timer = null;
 
// 로딩 시작 처리
function startLoading() {
	$("#loading").show();
 
	timer = setInterval(function() {
		$("#loading").append(".");
	},100);
} 
 
// 로딩 끝 처리
function stopLoading() {
	$("#loading").hide();
 
	clearInterval(timer);
	timer = null;
}
 
// 로딩 시작하기
startLoading();
 
// Ajax 불러오기
$.ajax({
	url: "http://api.flickr.com/services/rest/?method=flickr.interestingness.getList&api_key=d7cf8651384b2e99038ecf497b440421&format=json&nojsoncallback=1&auth_token=72157627258910199-5bc337cbd1122195&api_sig=9de8ad17087c2026f670fb26478c48bb",
	type: "get",
	dataType: "json", // 리턴받을 데이터의 타입 - text, xml 등...
	data: { // 파라미터		
	},
	success: function(data) { // 성공했을 때의 처리 콜백함수
		$("#result").append("success<br />");
 
		$(data.photos.photo).each(function() {
			// 박스 만들기
			var html = "<div style='float:left;margin:0 10px 10px 0;'><img src='http://farm"+this.farm+".static.flickr.com/"+this.server+"/"+this.id+"_"+this.secret+"_s.jpg' /></div>";
			$("#list").append(html);
 
			// 박스에 클릭이벤트 정의
			$("#list").children(":last-child").click(function() {
				// 페이드 아웃 효과 후 삭제
				$(this).fadeOut(function() {
					$(this).remove();
				});
			});
		});		
	},
	complete: function() { // ajax 전송이 완료 됐을 때의 콜백함수
		stopLoading();
 
		$("#result").append("complete<br />");
	},
	error: function() { // 에러가 발생했을 때의 콜백함수
		$("#result").append("error<br />");
	}
});
</script>

참고

  • 위키피디아의 AJAX
  • jQuery AJAX Reference
  • Date 객체와 Timing 관련 메소드

    Timing

    setTimeout

    setTimeout 메소드는 지정된 시간 이후에 함수를 실행시킵니다.

    clearTimeout

    clearTimeout 메소드는 setTimeout을 시켰을 경우 타이머가 동작하게 되는데 이 타이머를 해제하는 역할을 합니다.

    setInterval

    setTimeout 메소드는 지정된 시간 이후에 단 한 번만 함수를 실행시키는 반면에 setInterval 메소드는 지정된 시간마다 함수를 실행시킵니다.

    clearInterval

    clearTimeout 메소드는 setInterval 메소드로 타이머를 동작시켰을 때 해제하는 역할을 합니다.

    Example

    예제보기

    HTML

    1
    2
    3
    4
    5
    6
    7
    
    <div id="clock" style="margin-bottom:10px;">&nbsp;</div>
    <button id="stopClock">시간아 멈춰라!</button>
     
    <hr style="margin:10px 0 10px 0;" />
     
    <div id="fivesec" style="display:none;border:1px solid #000;">5초 후 보여주는 레이어</div>
    <button id="dontdisplay">안봐!</button>

    Javascript

    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
    
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script>
    // 5초 후에 5초 레이어 보여주기
    var timer1 = setTimeout(function() {
    	// 팝업 보여주기
    	$("#fivesec").show();
    },5000);
     
    // 5초 팝업 타이머 해제하는 액션
    $("#dontdisplay").click(function() {
    	clearTimeout(timer1);
    	timer1 = null;
    });
     
    // ---------------------------
     
    // 시계
    var timer2 = setInterval(function() {
    	// 현재시간 불러와서 변수에 저장
    	var d = new Date();
     
    	// 현재시간 출력
    	$("#clock").html(d.toString());
    },1000);
     
    // 시간 멈추는 액션
    $("#stopClock").click(function() {
    	// 타이머 해제
    	clearInterval(timer2);
    	timer2 = null;
    });
    </script>

    Date 객체

    자바스크립트에서는 날짜에 관한 기본적인 것들은 Date 객체가 담당하게 됩니다.
    예를들면 현재시간을 가져온다거나, 1월1일이 무슨 요일인지 등을 할 수 있는 객체입니다.

    참조 URL

    아래 링크에서 Date 객체의 모든 것을 확인 할 수 있습니다.
    http://w3schools.com/jsref/jsref_obj_date.asp

    Example

    예제보기

    Javascript

    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
    
    <script>
    // ---- 함수 정의부
     
    // 타이머 변수 생성 - 전역
    var timer_start = null;
    var timer_end = null;
     
    // 시작시간 구하기 함수
    function startTimer() {
    	timer_start = new Date();
    }
     
    // 정지시간 구하기 함수
    function stopTimer() {
    	timer_end = new Date();
    }
     
    // 시간 계산하기
    function getTimer() {
    	var result = timer_end.getTime()-timer_start.getTime();
    	console.log(result+"ms");
    }
     
    // ---- 구현부
    startTimer(); // 시작시간 구하기 함수 실행
    for(var i=0;i<100000000;i++) {
    	var a = 1;
    }
    stopTimer(); // 정지시간 구하기 함수 실행
    getTimer(); // 시간 계산해서 콘솔로 출력
    </script>

    .data() – jQuery API

    설명

    data()는 선택된 요소와 함께 연결된 데이터를 임의로 저장하거나 가져올 수 있습니다. val(), text(), html() 등과 같은 get/set 메소드입니다.

    jQuery 1.4.3 버전부터는 HTML5 data 속성이 jquery 데이터로부터 자동으로 만들어지게 됩니다.

    예제

    HTML

    1
    2
    3
    4
    5
    
    <div id="data" style="border:1px solid blue;margin:10px;padding:10px;">나는 데이터! 나의 데이터는 겉으로 보이지 않아...</div>
     
    <button id="btnViewData">데이터 보기</button>
    <button id="btnStoreData">데이터 저장</button>
    <button id="btnRemoveData">데이터 제거</button>

    Javascript

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script>
    // 데이터 보기
    $("#btnViewData").click(function() {
    	var content = $("#data").data("content");
     
    	alert("숨겨져 있는 데이터는 바로...\n\n'"+content+"'");
    });
     
    //데이터 저장
    $("#btnStoreData").click(function() {
    	$("#data").data("content","속에 감춰진 데이터는 바로 1");
     
    	alert("데이터가 저장되었습니다.");
    });
     
    //데이터 제거
    $("#btnRemoveData").click(function() {
    	$("#data").removeData("content");
     
    	alert("데이터가 제거되었습니다.");
    });
    </script>

    URL

    .data() – jQuery API.
    http://ejohn.org/blog/html-5-data-attributes/
    http://www.w3.org/TR/html5/elements.html#embedding-custom-non-visible-data-with-the-data-attributes

    .contents() – jQuery API

    설명

    선택된 요소의 자식요소들을 모두 가져옵니다. children()은 자식요소 중 일반 노드만을 가져오는 반면에, contents()는 일반노드 외에도 텍스트노드와 주석노드까지 가져옵니다.

    내용을 검색했을 때 내용에 검색어에가 있을 때 검색어에 배경색을 표시하는 기능등에 사용할 수 있을 것 같습니다.

    예제

    다음 예제는 p 태그안에 있는 내용중 Hello 단어가 있다면 볼드 처리를 하는 간단한 예제입니다.

    HTML

    1
    2
    3
    
    <p>
    Hello <a href="http://ejohn.org/">John</a>, how are you doing?
    </p>

    Javascript

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script>
    // P 요소안의 모든 내용 불러오기
    $("p").contents().each(function() {
    	// 선택된 노드의 텍스트를 불러옴.
    	var text = $(this).text();
     
    	// Hello 라는 단어가 있으면 b태그로 감싸기
    	if(text.match("Hello")) {
    		$(this).wrap("<b style='color:blue;'></b>");
    	}
    });
    </script>

    URL

    .contents() – jQuery API.

    getElementsByClassName 메소드에 대해서

    getElementsByClassName 메소드의 용도

    클래스명을 가지고 요소를 선택할 때 사용하는 메소드로 웹킷 전용 메소드입니다. getElementsByTagName과 같이 선택된 요소의 배열을 리턴해 줍니다.

    이 메소드를 쓰는 것이 따로 JS 라이브러리로 구현하거나 XPATH를 사용하는 것보다 엄청나게 빠릅니다.

    지원되지 않는 브라우저에서 대체하는 방법

    IE9에서는 지원하는 반면에 IE 6,7,8은 지원하지 않기 때문에 getElementsByTagName 함수를 직접 만들어 줘야 합니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    // 미지원 브라우저에서는 메소드 정의
    if(typeof(document.getElementsByClassName) !== "function") {
    	document.getElementsByClassName = function(className) {
    		var arr = [];
    		var ele = document.getElementsByTagName("*");
    		var cnt = ele.length;
     
    		for(var i=0;i<cnt;i++) {
    			if((" "+ele[i].className+" ").indexOf(" "+className+" ") > -1) {
    				arr.push(ele[i]);
    			}
    		}
     
    		return arr;
    	};
    }

    .filter() – jQuery API

    .filter()란?

    jQuery의 filter 메소드는 선택된 셀렉터 중에서 filter 메소드의 인자(selector, function, element, jquery object)와 일치되는 요소들만을 골라내는 기능을 합니다.

    .filter()와 .find()의 차이점

    .find()는 선택된 요소의 자식 또는 후손을 필터링 하는 반면에 .filter()는 선택된 요소들만을 필터링 합니다.

    find() 예제

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    <ul>
    	<li>1</li>
    	<li>2</li>
    	<li class="sel">3</li>
    	<li>4</li>
    	<li>5</li>
    </ul>
     
    $("ul").find(".sel").css("background-color","red");

    filter() 예제

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    <ul>
    	<li>1</li>
    	<li>2</li>
    	<li class="sel">3</li>
    	<li>4</li>
    	<li>5</li>
    </ul>
     
    $("ul li").filter(".sel").css("background-color","red");

    URL

    .filter() – jQuery API.

    자바스크립트 DOM

    Dom 이란?

    Document Object Model의 약자로 HTML을 제어 할 수 있는 API의 역할을 합니다.

    DOM의 처리 순서

    • 제어 대상 탐색
    • 제어 대상 메소드 실행 및 이벤트 핸들러 등록

    Dom Method

    • createElement : HTML 요소를 생성
    • appendChild : 자식에 요소를 추가
    • getAttribute : 속성을 가져옴
    • setAttribute : 속성을 넣음
    • getElementById : ID속성으로 요소를 가져옴
    • getElementsByName : NAME속성으로 요소를 가져옴(배열)
    • getElementsByTagName : 엘리먼트명으로 요소를 가져옴(배열)

    이러한 Dom 메소드를 어떻게 사용하는지 알아보도록 하겠습니다.

    예제 링크

    HTML

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    <h1>testByTagName - 색 변경 - getElementsByTagName 예제</h1>
    <ul id="test1">
    	<li>1</li>
    	<li>2</li>
    	<li>3</li>
    	<li>4</li>
    	<li>5</li>
    </ul>
     
    <h1>testByName - 색 변경, getElementsByName 예제</h1>
    <ul id="test2">
    	<li name="li_name">1</li>
    	<li name="li_name">2</li>
    	<li name="li_name">3</li>
    	<li name="li_name">4</li>
    	<li name="li_name">5</li>
    </ul>
     
     
    <h1>drawBox - 박스 그렸다 5초만에 지우기</h1>

    Javascript

    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
    
    <script type="text/javascript">
    //DIV 박스를 body 태그 안에 추가해주는 함수
    function drawBox() {
    	// DIV 요소 생성
    	var div = document.createElement("div");
     
    	// DIV의 속성 지정 (id, style)
    	div.setAttribute("id","testDiv");
    	div.setAttribute("style","border:1px solid #000000;padding:10px;height:100px;");
     
    	// DIV 내용으로 위에서 지정한 속성을 출력 
    	div.innerHTML = div.getAttribute("style");
     
    	// DIV를 body 태그안에 추가해준다. 
    	document.body.appendChild(div);
     
    	// 5초 보여주고 지우기
    	setTimeout(function() {
    		// 요소 제거
    		document.body.removeChild(div);
    	},5000);
    }
     
    function testByTagName() {
    	// test1이란 아이디를 가진 요소를 JS 변수로 선언
    	var test2 = document.getElementById("test1");
     
    	// test2에서 tagName으로 검색해서 li인 것만 찾아서 배열로 저장
    	var arrLi = test2.getElementsByTagName("li");
     
    	// 배열 갯수
    	var cnt = arrLi.length;
     
    	// 배열 루프
    	for(var i=0;i<cnt;i++) {
    		// 선택된 li 요소의 색상 변경
    		arrLi[i].setAttribute("style","color:red;");
    	}
    }
     
    function testByName() {
    	var arrLi = document.getElementsByName("li_name");
     
    	// 배열 갯수
    	var cnt = arrLi.length;
     
    	// 배열 루프
    	for(var i=0;i<cnt;i++) {
    		// 선택된 li 요소의 색상 변경
    		arrLi[i].setAttribute("style","color:blue;font-size:14px;");
    	}
    }
     
    // 함수 실행
    drawBox();
    testByName();
    testByTagName();
    </script>

    jQuery 에서는?

    Manipulation – 조작

    • append : 자식요소를 가장 뒤에 추가한다.
    • prepend : 자식요소를 가장 앞에 추가한다.
    • after : 형제요소를 뒤에 추가한다.
    • before : 형제 요소를 앞에 추가한다.
    • attr : 속성을 가져오거나 지정할 수 있다.(get/set)
    • html : 선택된 요소 안에 HTML을 가져오거나 지정할 수 있다.(get/set)
    • text : 선택된 요소 안에 텍스트만 가져오거나 지정할 수 있다.(get/set)
    • val : 선택된 요소의 value 값을 가져오거나 지정할 수 있다.(get/set)
    • css: 선택된 요소의 css 값을 가져오거나 지정할 수 있다.(get/set)
    • remove : 선택된 요소를 삭제한다.

    Traversing – 탐색(?)

    • find : 선택된 요소 아래에 있는 요소를 검색해서 선택한다.
    • next : 선택된 요소 다음 요소를 선택한다.
    • prev : 선택된 요소 이전 요소를 선택한다.
    • parent : 선택된 요소의 부모 요소를 선택한다.
    • children : 선택된 요소의 자식 요소를 선택한다.

    Javascript 이벤트

    이벤트란?

    웹페이지에서 사용자가 클릭을 하거나 키보드 입력과 같은 상호작용을 하게 되는데, 클릭이나 키 입력과 같이 발생하는 것을 이벤트라고 합니다.
    창 사이즈를 조절하거나 스크롤을 내리거나 올릴 때에도 이벤트는 발생합니다.
    이벤트가 발생했을 때 실행되는 메소드를 이벤트 핸들러라고 합니다.

    IE에서 이벤트 추가하기

    1
    
    element.attachEvent(event, callback);

    표준 브라우저에서 이벤트 추가하기

    1
    
    element.addEventListener(event, callback, useCapture);

    이벤트 추가하는 함수

    IE와 표준브라우저에서 사용할 수 있는 함수를 만들어 보겠습니다.

    1
    2
    3
    4
    5
    6
    7
    
    function addEvent(ele,evt,callback, useCapture) {	
    	if(ele.addEventListener) {
    		ele.addEventListener(evt,callback, useCapture);
    	} else if(ele.attachEvent) {
    		ele.attachEvent("on"+evt, callback);
    	}
    }

    IE와 표준 브라우저의 이벤트에 대한 차이점

    이벤트를 등록, 해제하는 메소드가 다르다.
    IE : attachEvent, detachEvent
    표준 브라우저 : addEventListener, removeEventListener

    이벤트 지정 문자열이 다르다. IE의 경우는 앞에 on이 붙음.

    이벤트 객체를 받는 방법이 다르다.
    IE : window.event 객체로 전달 받음.
    표준 브라우저 : callback 함수에서 인자로 전달 받음.

    기본 이벤트의 실행 방지 방법이 다르다.
    IE : return 값에 의해서 결정된다.
    표준 브라우저 : preventDefault 메소드를 사용해서 결정한다.

    자주 사용하는 이벤트 리스트

    click : 마우스 클릭
    mouseover : 마우스 오버
    mouseout : 마우스 아웃
    change : 셀렉트박스의 값이 달라졌을 때
    scroll : 스크롤 되었을 때
    resize : 사이즈가 변경 되었을 때
    keyup : 키가 눌린 후 뗄 때
    focus : 포커스
    blur : 포커스 해제 되었을 때

    캡쳐와 버블링

    이벤트는 최상위 엘리먼트로부터 이벤트가 발생한 엘리먼트까지 찾아 들어간 후 다시 최상위 요소까지 올라가며 이벤트를 발생 시킵니다
    여기서 이벤트가 발생한 엘리먼트까지 들어가는 과정을 이벤트 캡쳐라 하고, 최상위 요소까지 다시 올라가는 과정을 이벤트 버블링이라고 합니다.

    예제

    지금까지 얘기한 이벤트를 실제 사용한 예제를 만들어보도록 하겠습니다.

    HTML

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    <h1>Event Test</h1>
    <div id="wrap">
    	<div id="wrap2">
    		<button id="test_btn">click</button>
    	</div>
    </div>
     
    <h1>DEBUG <button id="clear">clear</button></h1>
    <div id="console"></div>

    CSS

    1
    2
    3
    
    #wrap {border:1px solid #000000;padding:10px;margin-bottom:10px;}
    #wrap2 {border:1px solid #E2E2E2;padding:10px;margin-bottom:10px;}
    #console {height:400px;overflow-y:scroll;border:1px solid #E2E2E2;padding:10px;}

    Javascript

    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
    
    <!-- 스크립트 영역 -->
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
    <script type="text/javascript">
    // HTML 엘리먼트를 자바스크립트 변수로 저장
    var wrap = document.getElementById("wrap"); // 감싸는 레이어
    var wrap2 = document.getElementById("wrap2"); // 감싸는 레이어2
    var clear_btn = document.getElementById("clear"); // 클리어 버튼
    var test_btn = document.getElementById("test_btn"); // 클릭 버튼
    var consol_div = document.getElementById("console"); // 콘솔창
     
    // 카운트 변수 정의
    var logCnt = 1;
     
    // 로그를 출력하기 위한 함수
    function logConsole(msg) {
    	consol_div.innerHTML = logCnt+" : "+msg+"<br />"+consol_div.innerHTML;
    	logCnt++;
    }
     
    // 로그 초기화 함수
    function clearConsole() {
    	consol_div.innerHTML = "";
    	logCnt = 1;
    }
     
    // 이벤트 등록을 위한 브라우저 호환을 위한 함수 정의
    function addEvent(ele,evt,callback, useCapture) {	
    	if(ele.addEventListener) {
    		ele.addEventListener(evt,callback, useCapture);
    	} else if(ele.attachEvent) {
    		ele.attachEvent("on"+evt, callback);
    	}
    }
     
    /*** 구현 ***/
     
    // 로그 clear 버튼 클릭 이벤트 걸기
    addEvent(clear_btn,"click", function(e) {
    	clearConsole();
    },false);
     
    // 감싸는 레이어 클릭 이벤트 걸기
    addEvent(wrap,"click", function(e) {
    	logConsole("wrap click");
    },false);
     
    //감싸는 레이어2 클릭 이벤트 걸기
    addEvent(wrap2,"click", function(e) {
    	logConsole("wrap2 click");
    },false);
     
    // 버튼 클릭 이벤트 걸기
    addEvent(test_btn,"click", function(e) {
    	// 표준 브라우저일 경우
        if(typeof(e.stopPropagation) == "function") {
        	 e.stopPropagation();    	
        } else { // IE 일 경우           
        	window.event.cancelBubble = true;   	
        } 
     
    	logConsole("button click");
    },false);
    </script>

    숙제

    1. 현재 logConsole로 출력하는 부분을 각 엘리먼트(wrap, wrap2, test_btn)의 배경색(background-color)을 바뀌도록 수정하시오.
    2. 감싸는 레이어2(wrap2)에서 버블링이 일어나지 않도록 수정하시오.

    모달창 만들기

    이번 시간에는 모달창을 만들어 보겠습니다.

    모달창은 보통 배경은 어둡게 되고, 팝업 레이어가 뜨는 형태로 많이 사용되고 있습니다.
    모달창을 만들기 위해서는 모달창에 어떤기능을 넣을지 기능정의를 해야 합니다.

    • 보여주기
    • 감추기
    • 배경 어둡게 하는 레이어 생성
    • 가운데 보여주기

    간단하게 기능정의를 해봤는데, 이정도 기능을 가진 모달창을 어떻게 만드는지 알아보도록 하겠습니다.

    먼저 HTML과 CSS를 정의를 합니다.

    HTML

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    <!-- 모달 창을 여는 버튼 -->
    <button id="button">Open Modal</button>
     
    <!-- 모달창 -->
    <div id="modal">
    	<h3>Test Modal</h3>
    	<p>이 창은 모달창입니다.</p>
    	<button id="confirm_button">확인</button>
    	<button class="js_close">닫기</button>
    </div>

    CSS

    1
    
    #modal {display:none;background-color:#FFFFFF;position:absolute;top:300px;left:200px;padding:10px;border:2px solid #E2E2E2;z-Index:9999}

    버튼이 하나가 있고, 감춰진 레이어(모달창)가 있습니다.
    버튼을 누르면 감춰진 레이어가 모달창으로 나타나게 되고, 확인 버튼이나 닫기 버튼을 누른다는 것이 예상되는 HTML 입니다.

    Javascript

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    <!-- 스크립트 영역 -->
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
    <script type="text/javascript" src="Example.Modal.js"></script>
    <script type="text/javascript">
    // 모달창 인스턴트 생성
    var myModal = new Example.Modal({
    	id: "modal" // 모달창 아이디 지정
    });
     
    // 모달 창 여는 버튼에 이벤트 걸기
    $("#button").click(function() {
    	myModal.show(); // 모달창 보여주기
    });
     
    // 모달 창 안에 있는 확인 버튼에 이벤트 걸기
    $("#confirm_button").click(function() {
    	alert("나는 모달창이다.");
    	myModal.hide(); // 모달창 감추기
    });
    </script>

    자바스크립트를 살펴 보면, 3가지 액션을 합니다.

    • 모달창 인스턴트 생성
    • 모달 창 여는 버튼에 이벤트 걸기
    • 모달 창 안에 있는 확인 버튼에 이벤트 걸기

    Example.Modal.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
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    
    if(typeof(Example) == "undefined") var Example = {};
     
    (function($){
    	Example.Modal = function() {
    	this.initialize.apply(this,arguments);
    }
     
    Example.Modal.prototype = {
    	initialize : function(hash) {
    		var obj = this;
     
    		// 멤버변수 정의
    		this.hash = this.getHashData(hash);
    		this.width = 0; // 콘텐츠 레이어 너비
    		this.height = 0; // 콘텐츠 레이어 높이
    		this.c_width = 0; // body 화면 너비 
    		this.c_height = 0; // body 화면 높이
    		this.s_width = 0; // body 전체 너비
    		this.s_height = 0; // body 전체 높이
     
    		// 콘텐츠 레이어 사이즈 구하기(멤버변수에 저장)
    		this.getLayerSize();
     
    		// body 사이즈 구하기(멤버변수에 저장)
    		this.getBodySize();
     
    		// 추가 엘리먼트 생성
    		this.addElement();
     
    		// 마우스, 키 이벤트 정의
    		this.addEvent();
    	},
     
    	// Hash 변수정의
    	getHashData : function(hash) {
    		if(typeof(hash.id) == "undefined") hash.id = "modal"; // 개체 아이디
    		if(typeof(hash.is_slide) == "undefined") hash.is_slide = 0; // 슬라이딩 여부
     
    		return hash;
    	},
     
    	// 추가 엘리먼트 생성 - JS에서 추가해 주어야 할 HTML 작성합니다.
    	addElement : function() {
    		// 배경 레이어 HTML 받아오기
    		var html = this.addOverlay();
     
    		// 배경레이어 HTML을 콘텐츠레이어 앞에 추가
    		$("#"+this.hash.id).before(html);
    	},
     
    	// 마우스, 키 이벤트 정의
    	addEvent : function() {
    		var obj = this;
     
    		// 닫기 버튼 클릭 이벤트 정의
    		$("#"+this.hash.id+" .js_close").click(function() {
    			// 모달창 감추기(여기서 obj는 Example.Modal 인스턴트 자체를 의미)
    			obj.hide();
    		});
    	},	
     
    	/* 주요기능 */
     
    	// 모달창 보여주기
    	show : function() {
    		// 가운데로 이동
    		this.moveCenter();
     
    		// 배경레이어 적용
    		this.applyOverlay();
     
    		// 콘텐츠 레이어 보여주기
    		$("#"+this.hash.id).show(); 
     
    		// 배경 레이어 보여주기
    		$("#"+this.hash.id+"_overlay").show();  
    	},
     
    	// 모달창 감추기
    	hide : function() {
    		$("#"+this.hash.id).hide(); // 콘텐츠 레이어 감추기
    		$("#"+this.hash.id+"_overlay").hide(); // 배경 레이어 감추기 
    	},	
     
    	/* 부가 기능 */
     
    	// 콘텐츠 레이어의 너비와 높이를 구해서 멤버변수에 정의
    	getLayerSize : function() {
    		this.width = $("#"+this.hash.id).outerWidth();
    		this.height = $("#"+this.hash.id).outerHeight();
    	},
     
    	// body 사이즈 구해서 멤버변수에 정의
    	getBodySize : function() {
    		this.c_width = document.documentElement.clientWidth;
    		this.c_height = document.documentElement.clientHeight;
    		this.s_width = document.documentElement.scrollWidth;
    		this.s_height = document.documentElement.scrollHeight;
    	},
     
    	// 배경 레이어 HTML 생성
    	addOverlay : function() {
    		var html = "";
    		html += "<div id='"+this.hash.id+"_overlay' style='display:none;width:100%;position:absolute;top:0px;left:0px;opacity:0.5;background-color:#000000;z-Index:999'></div>";
     
    		return html;
    	},
     
    	// 콘텐츠 레이어를 가운데로 이동(top, left 조절해 줌)
    	moveCenter : function() {
    		// left 좌표 구하기
    		var left = Math.floor((this.c_width-this.width)/2);
     
    		// top 좌표 구하기
    		var res_height; // 콘텐츠를 화면상의 가운데로 두었을 때의 높이
    		if(this.c_height < this.height) { // 화면 높이 < 콘텐츠 레이어 높이
    			res_height = 0; 
    		} else { // 화면 높기 >= 콘텐츠 레이어 높이
    			res_height = Math.floor((this.c_height-this.height)/2); // 차이를 빼서 2로 나눔. 그리고 내림. 
    		}
    		var top = res_height+$(document).scrollTop(); // 화면상의 높이에 스크롤높이를 더한 절대좌표를 top에 저장
     
    		// css의 top,left 조정
    		$("#"+this.hash.id).css("top",top);
    		$("#"+this.hash.id).css("left",left);
    	},
     
    	// 배경 레이어 적용
    	applyOverlay : function() {
    		// body 사이즈 구하기(멤버변수에 저장)
    		this.getBodySize();
     
    		// 배경 레이어에 width, height css 값 조정
    		$("#"+this.hash.id+"_overlay").css("width",this.s_width);
    		$("#"+this.hash.id+"_overlay").css("height",this.s_height);
    	}
    }
     
    })(jQuery);

    소스가 긴데 크게 보면(메소드 단위) 간단한 소스입니다.
    아래 화면을 보면 이클립스가 있고, 우측에 아웃라인 뷰라고 해서, JS 클래스의 구조를 볼 수 있는 편리한 뷰가 생깁니다.
    이클립스의 장점이죠.

    어쨌든 이 메소드들이 어떤 일을 하는지 알아보도록 하겠습니다.

    initialize

    인스턴트를 생성했을 때 초기화를 시켜주는 생성자입니다. 인스턴트 생성되었을 때 하는 모든일은 여기서 정의하게 됩니다.
    getLayerSize(), getBodySize(), addElement(), addEvent() 메소드를 실행시켜주게 됩니다. 이 메소드에서는 아래부분에서 알아보도록 하겠습니다.

    getHashData

    다음과 같은 부분이 있는데, getHashData 메소드를 실행시키고 그 반환값을 멤버변수인 this.hash에 집어넣는다는 의미입니다.
    이 메소드는 자바스크립트 인스턴트의 기본(default)값을 정의하는 역할을 합니다.

    13
    
    		this.hash = this.getHashData(hash);

    addElement

    추가 엘리먼트를 생성합니다. 모달창 div 나 버튼 같은 요소들은 Javascript로 처리되기 전에 있어도 상관 없지만, 백그라운드 레이어 같은 경우는 모달창이 뜰때만 필요한 부분일 수도 있기 때문에 동적으로 생성되는게 더 효율적이라고 생각이 됩니다.

    addEvent

    모듈에 관련된 요소들에 이벤트를 걸어줍니다.
    여기서는 모달창 모듈의 닫기 버튼에 클릭이벤트를 걸었습니다.

    show

    가장 중요한 보여주기 기능입니다.
    콘텐츠 레이어를 가운데로 옮기고, 배경레이어 사이즈 조정 후 콘텐츠와 배경레이어를 보여줍니다.

    hide

    감추는 기능입니다.
    모달창과 배경레이어를 감추는 내용입니다.

    getLayerSize

    콘텐츠 레이어의 너비와 높이를 구하는 메소드입니다.
    가운데 정렬하기 위해서 필요한 수치이기 때문에 이 메소드를 따로 두게 되었습니다.

    getBodySize

    body의 너비와 높이를 구하는 메소드입니다.
    이 메소드 역시 가운데 정렬을 하기 위해 필요합니다.

    addOverlay

    단순히 배경 레이어를 생성하고, css를 in-line으로 정의되어서 독립적으로 쓸 수 있습니다.

    moveCenter

    위 메소드를 실행시켜 구한 수치들을 이용해서 계산을 하는 메소드입니다.
    마지막에는 css의 top, left 의 수치를 변화시켜서 가운데 정렬을 하게됩니다.

    applyOverlay

    배경 레이어의 사이즈를 body의 사이즈에 따라서 변화를 시킵니다.
    이 메소드는 resize를 할 때 body의 사이즈가 달라졌을 경우 실행시키도록 하면 항상 body를 덮는 배경레이어를 만들 수 있습니다.

    자바스크립트로 OOP 구현하기

    자바스크립트로 개발하기 위해서 필요한 개념에 대해서 알아보도록 하겠습니다.

     

    데이터 타입

    • 객체(Object) : 예) {name: “정기철”, age: 30}
    • 배열(Array) : 예) [1,2,3]
    • 문자열(String) : 예) “abc123″
    • 숫자(int,float) : 예) 1
    • Boolean : 예) true , false

    JSON

    경량의 데이터 교환방식입니다. 그리고 자바스크립트에서는 객체에 속합니다.

     

    예) var rss = [

    {no: 1, title: "블로그글 제목1", content:  "블로그 내용1",  wdate: "2011-06-25"},

    {no: 2, title: "블로그글 제목2", content:  "블로그 내용2",  wdate: "2011-06-27"}

    ];

     

    JSON에 대한 자세한 내용은 다음 링크를 참고해주세요.

    JSON의 개요

     

    객체지향 프로그래밍(OOP)

    OOP는 대상을 객체로 정하고 이를 다루는 개념입니다. 자바스크립트가 OOP를 기본적으로 지원하지 않지만 OOP와 같이 개발할 수 있습니다.

     

    주요 용어

    • Class : 다루고자 하는 대상으로 객체라고도 합니다. 객체는 Method와 Attribute로 정의되어 있습니다.
    • Instance : Class에 정의되어 있는 것을 바탕으로 만들어진 활성체를 말하며 개체라고 합니다.
    • Method : 메소드, 멤버함수라고도 하면 객체에서 행동을 담당하는 부분입니다. 보통 동사+목적어 카멜표기법을 사용합니다.
    • Attribute : 속성, 멤버변수라고도 하며 객체의 속성입니다.

     

    객체의 특징

    • 추상화 : 객체는 속성과 메소드로 정의됩니다.
    • 캡슐화(은닉) : 객체는 블랙박스와 같을 수 있습니다. 안에서 어떻게 처리되는 것은 중요하지 않고, 해당 객체의 인터페이스만을 알면 다룰 수 있습니다.
    • 상속 : 슈퍼클래스나 부모클래스에 정의되어 있는 내용을 상속 받을 수 있습니다. 상속도 자바스크립트로 구현 가능합니다.

     

    기타 OOP와 관련된 자세한 내용은  관련 서적이나 참고자료가 많이 있으니 참고하시기 바랍니다.

     

    모듈 개발을 위한 기본 OOP 패턴

    이제부터 자바스크립트에서 객체지향 프로그래밍의 형태로 개발해 보도록 하겠습니다.

    아래 패턴은 모듈이나 페이지를 개발하기 위해 개인적으로 만들었고, 다른 형태로도 OOP를 구현할 수 있습니다.

     

    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
    
    if(typeof(Module) == "undefined") var Module = {};
     
    (function($){
     
    Module.Template = function() {
    	this.initialize.apply(this,arguments);
    }
     
    Module.Template.prototype = {
    	initialize : function(hash) {
    		var obj = this;
     
    		this.hash = this.getHashData(hash);
    		this.addElement();
    		this.addEvent();
    	},
     
    	getHashData : function(hash) {
    		if(typeof(hash.id) == "undefined") hash.id = "";
     
    		return hash;
    	}
    }
     
    })(jQuery);

    L1 : Module이라는 네임스페이스를 전역으로 정의합니다.
    L3 ~ L31 : Template라는 클래스를 정의합니다.

    Module.Template 클래스에는 3개의 메소드로 구성되어 있습니다.

    1. initialize : 생성자의 역할을 합니다. 실행과 동시에 getHashData와 addEvent 메소드를 실행시켜줍니다.
    2. getHashData : 생성자를 통해 넘어온 데이터를 처리하고, 변경된 결과를 리턴합니다.
    3. addEvent : HTML 개체에 이벤트를 일괄적으로 추가해주는 역할을 합니다.

     

    실습 예제

    이제 위의 패턴을 이용해서 간단한 예제를 만들어서 실행시켜보도록 하겠습니다.

    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
    
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
    <title>OOP 테스트 프로그램</title>
    </head>
     
    <body>
    <button id="person1">신짱구</button>
    <button id="person2">나미리</button>
     
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
    <script type="text/javascript" src="data.js"></script>
    <script type="text/javascript" src="Module.Example.js"></script>
    <script type="text/javascript">
    // 인스턴스 생성
    var P1 = new Module.Person({ // 신짱구
    	id: "person1",
    	data: data1
    });
    var P2 = new Module.Person({ // 나미리
    	id: "person2",
    	data: data2
    });
    </script>
    </body>
    </html>

    data.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    // 데이터 정의
    var data1 = {
    	name: "신짱구",
    	age: 5
    }
    var data2 = {
    	name: "나미리",
    	age: 22
    }

    Module.Example.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
    
    // 클래스 정의
    if(typeof(Module) == "undefined") var Module = {};
     
    (function($){
     
    Module.Person = function() {
    	this.initialize.apply(this,arguments);
    }
     
    Module.Person.prototype = {
    	initialize : function(hash) {
    		var obj = this;
     
    		this.hash = this.getHashData(hash);
    		this.addEvent();
    	},
     
    	getHashData : function(hash) {
    		if(typeof(hash.id) == "undefined") hash.id = "";
    		if(typeof(hash.data) == "undefined") hash.data = {};
     
    		return hash;
    	},
     
    	addEvent : function() {
    		var THIS = this;
     
    		$("#"+this.hash.id).mouseover(function() {
    			THIS.alertName();
    		}).mouseout(function() {
    			THIS.alertAge();
    		});
     
    	},
     
    	alertName : function() {
    		console.log("내 이름은 "+this.hash.data.name+"입니다.");
    	},
     
    	alertAge : function() {
    		var who;
     
    		if(this.hash.data.age > 19) {
    			who = "어른";
    		} else {
    			who = "미성년자";
    		}
     
    		console.log(this.hash.data.age+"살 "+who+"에요.");
    	}	
    }
     
    })(jQuery);