본문 바로가기

JSP & WEB & Ajax

jQuery로 작업하기 Part 2


jQuery로 작업하기, Part 2: 내일 나올 웹 응용을 오늘 구현해보자

사건, 속성, CSS

developerWorks

 

 

 

 


제안 및 의견
피드백

난이도 : 중급

Michael Abernethy, 제품 개발 관리자, Optimal Auctions

옮긴이: 박재호 이해영 dwkorea@kr.ibm.com

2008 년 11 월 25 일

jQuery 연재물 중 두 번째 기사에서는 풍부한 RIA(Rich Internet Application)를 만들기 위해 웹 사이트에 상호 대화식 기능을 추가하는 방법을 설명하겠습니다. jQuery와 관련해 사용자가 만들어낸 사건, 웹 사이트 자체에서 얻은 정보를 결합해 활용하는 방법을 다루며, 이런 RIA를 빠르고 쉽게 만들기 위해 화면을 새로 고치지 않고도 응용 프로그램의 외형과 느낌을 변경하는 기능을 소개하겠습니다.

도입

jQuery는 지난 6개월 동안 급속도로 퍼져나가고 있으며, 웹 개발자를 위한 자바스크립트 라이브러리로 자리잡고 있다. 이런 현상은 브라우저 기반 응용으로 데스크톱 응용을 교체하기 위한 RIA(Rich Internet Application) 활용과 필요성이 급격하게 증가하는 상황과 맞물려 돌아간다. 스프레드시트부터 급여 계산에서 전자편지 응용에 이르기까지 브라우저로 데스크톱 응용을 교체해 나가는 현실이다. 이런 응용 개수가 많아지고 복잡해지면서 자바스크립트 라이브러리는 응용을 만드는 튼튼한 기초로 더욱 더 중요성이 높아질 것이다. jQuery는 개발자를 위한 필수 라이브러리가 되었다. 이 연재물에서는 jQuery를 깊숙하게 탐험하며, 개발자가 RIA를 빠르고 쉽게 만들기 위한 튼튼한 토대를 제공한다.

지난 기사에서, 개발 환경에 jQuery를 설치하는 방법과 핵심 기능, 동작 원리를 포함한 jQuery 기초를 익혔다. jQuery가 선택/필터링 메서드를 사용해 페이지에 있는 엘리먼트를 찾는 쉽게 방법은 물론이고 찾고자 하는 단일 엘리먼트나 엘리먼트 그룹을 정확하게 찾아내는 방법도 살펴보았다. 그러고 나서 jQuery가 제공하는 선택 결과를 탐색하는 다양한 메서드와 다른 프로그래밍 언어에 익숙한 개발자를 위한 유사 함수를 살펴보았다. 마지막으로 예제 위젯인 Select All/Deselect All 체크박스를 대상으로 몇 줄만 추가해서 동작하는 jQuery 프로그램 구현 방식을 살펴보았다.

이번 기사에서는 낡은 인터넷 응용에 실질적인 "풍부함"을 제공해서 예제 프로그램에 RIA라는 레이블을 붙일 수 있도록 만드는 동시에 화려한 기능을 살펴봄으로써 jQuery 지식을 확장해 나간다. 먼저 jQuery가 사건을 다루는 방법을 보여준다. 사건은 마우스 클릭, 강조, 끌기 등으로 정의된다. 사건은 단순히 버튼에만 국한되지 않으며 div, span 등에 마우스 클릭을 할 때도 일어난다. 다음으로 넘어가서 웹 페이지에 들어있는 객체에서 속성을 얻고 설정하는 방법을 설명하겠다. 이는 form 엘리먼트에서 텍스트를 얻는 방법, div에서 innerHTML을 얻는 방법, 어떤 엘리먼트에 어떤 클래스가 붙어 있는지 파악하는 방법까지도 포함한다. 마지막 절은 페이지를 새로 고치거나 외부 스타일 시트를 변경하지 않고서도 페이지 엘리먼트의 CSS 특성을 변경하는 방법을 설명한다.

예제는 웹 메일 응용을 위한 추가 위젯을 포함하며, 클라이언트 쪽에서 동작하는 RIA를 만들어 페이지 내부에서 일어나는 상호 작용에 기반을 둔 색상, 크기, 객체 위치 변경 방법을 보여준다. (이번 기사에서는 상호 작용 설명을 클라이언트 단으로 제한한다. 다음 기사에서는 서버 쪽 상호 작용도 추가할 것이다). 이 기사를 끝까지 읽으면 독자적인 RIA를 생성해 고객에게 감동을 주는 모든 jQuery 도구를 갖출 것이다.

사건

jQuery에서 사건 모듈은 웹 응용에 상호 대화 기능을 추가하는 첫 번째 단계다. 사건은 페이지에서 일어나는 모든 행위를 시작하는 단초가 되기 때문이다. 도입부에서 지적했듯이, 사건이 form 엘리먼트에서만 일어난다고 생각하면 안 된다. 실제로 어떤 엘리먼트도 사건을 일으킬 수 있으며, 이를 활용해 특정 form 엘리먼트 자체에 묶이지 않고서도 전용 위젯을 좀 더 쉽게 만들어 여기에 독자적인 상호 작용을 추가할 수 있다.

이렇게 말하긴 했지만, 대다수 사건은 form 엘리먼트와 관련이 있으며, form 엘리먼트를 사용하는 예제를 보여주는 편이 가장 손쉽다. 사용 가능한 함수로 바로 들어가기 전에, 사건 모듈이 각 함수마다 특정 패턴을 따른다는 사실에 주목하자. 각 사건 함수는 두 가지 형태로 나뉜다. 하나는 인수가 없는 형태이며, 다른 하나는 인수로 함수를 포함하는 형태다. 양쪽을 구분하는 차이점은 중요하며 함수마다 일정한 규칙을 따른다. 매개변수가 없는 함수는 실제로 사건을 일으킨다. 다시 말해 click()을 호출하면 실제 버튼을 클릭한 상태로 만든다. 버튼을 실제로 눌렀을 경우나 click() 함수를 호출했을 때 click(function)을 호출한다. 헷갈리는가? 설명만 보면 그럴지 모르겠지만 예제를 보면 좀 더 명확해질 것이다.


Listing 1. jQuery 사건 메서드
				
// "myButton" 클릭 일으키기.  이렇게 하면 버튼을 클릭하며, 버튼에 붙어 있는
// 동작을 수행한다. 예를 들어, 폼을 제출하거나 관련된 다른 jQuery 동작을 수행한다.
$("#myButton").click();

// jQuery를 활용해 "myButton"을 실제로 클릭했을 때 무슨 일이 일어날지를 설정한다.
$("#myButton").click(function(){
   $("#myDiv").toggle();
});

// 페이지에서 동작을 설정할 때 사용하는 jQuery에서 일반적인 패턴은 페이지를 읽을 때
// 초기에 발생하도록 동작을 유도하는 방식이다. 이는 서버에서 값을 가져올 경우
// Ajax 설정 과정에서도 종종 나타난다.
// 이 예제에서, myDiv는 버튼을 클릭할 때마다 시각적으로 토글된다. 페이지를 읽을 때
// click()을 바로 호출하므로, 페이지가 뜨자마자 뷰를 토글한다(실질적인 예는 아니며,
// 설계 시 디자인을 검토해야 한다.
$("#myButton").click(function(){
   $("#myDiv").toggle();
}).click();

다음에 소개하는 사건은 직전에 소개한 설계 방식에 따라 함수 두 가지가 관련되어 있다. 지면 관계상 첫 번째 형식만 정리했다.

  • blur(): form 엘리먼트가 초점을 잃어버릴 때 호출된다. 탭 키로 이동하는 바람에 텍스트 필드에서 초점이 다른 필드로 넘어갈 때가 대표적이다.
  • change(): form 엘리먼트가 초점을 잃어버렸는데 앞서 초점을 얻은 이후에 값이 바뀐 경우에 호출된다. IE와 FF는 이 이벤트를 조금 다르게 취급한다.
  • click(): 페이지 엘리먼트를 클릭했을 때 호출된다(반드시 form 엘리먼트가 되어야 할 필요는 없다).
  • dblclick(): 페이지 엘리먼트를 클릭할 때 호출된다(반드시 form 엘리먼트가 되어야 할 필요는 없다).
  • error(): 엘리먼트에 내부 오류가 발생할 때 호출된다. 브라우저마다 다르며, 사람들이 이런 이벤트를 목격하기란 쉽지 않다.
  • focus(): form 엘리먼트가 초점을 얻을 때 호출된다.
  • keydown(): 페이지 엘리먼트에서 키를 누를 경우에 호출된다.
  • keyup(): 페이지 엘리먼트에서 키를 뗄 경우에 호출된다.
  • keypress(): 연속으로 빨리 동일 엘리먼트에 keydown과 keypress가 일어날 때 호출된다.
  • select(): 텍스트 필드에서 텍스트를 선택할 때 호출된다. 콤보 박스에서 선택되는 경우에는 호출되지 않는다(이 때는 change 이벤트가 발생한다).
  • submit(): 폼을 제출할 때 호출된다.

직전에 소개한 패턴을 따르지 않으므로 호출 가능한 함수 하나만 제공하는 경우도 있다. 여기서 예외만 따로 정리한 이유는 자주 쓰이지 않기 때문이다.

  • resize(fn): 객체 크기가 바뀔 때 호출된다.
  • scroll(fn): iframe에 스크롤이 일어날 때 호출된다.
  • load(fn)/unload(fn): 객체가 페이지에 올라오고 내려올 때 발생한다.

마지막으로 몇몇 사건은 이미 예상한 바와 같이 마우스에 묶여 있다. 이를 세 번째 절에 포함한 이유는 흔히 오용되기 쉽기에, 이런 문제를 파악한 jQuery에서는 몇 가지 함수를 독자적인 함수로 대체했기 때문이다. 여기서는 기반 DOM 사건에만 직접 사상한다. 하지만 실질적인 이유 때문에 실전에서 활용할 대체 메서드도 존재한다. 엘리먼트에 대해 마우스를 누르거나 뗄 때 mousedown(fn)mouseup(fn) 함수가 호출된다. 하지만 click() 메서드를 대신 호출하면 좋다. 사건 발생은 동일하지만 기대하는 행동 양식과 조화를 이루며 오류 발생 가능성도 낮기 때문이다. 사용자가 마우스 버튼을 누른 다음에 실수를 알아차리고 마우스 버튼을 떼기 전에 마우스를 버튼에서 옮길 경우를 생각해보자. mouseup(fn)이 정의된 다른 페이지 엘리먼트로 옮겨간 다음에 버튼을 떼면 어떤 동작이 일어날까? 이상적으로는 이런 두 함수는 끌어다 놓기 인터페이스에서만 동작해야 한다. 끌어다놓기 상황에서 click은 적합한 대체물이 아니다.

사건 모듈에서 나머지 두 메서드인 mouseover(fn)mouseout(fn)은 오늘날 대다수 웹 사이트에서 흔히 사용한다. 떠다니는 도움말, 그림 출력을 위한 그림자 상자, 마우스 포인터 위치에 따른 색상 변화 등에 쓰인다. jQuery는 이런 두 함수가 상당히 자주 쓰이는 반면에 대다수 사람이 올바른 용법을 따르지 않기에 무수한 오류를 발생시킨다는 사실을 인식했다. 사람들이 고의로 코드에 버그를 심는다는 말이 아니라 복잡한 페이지와 중첩된 구성 요소를 위한 코드를 올바르게 만들기 어렵다는 말이다. 따라서 jQuery는 이벤트 모듈에 이 두 함수를 대체할 hover(fn1, fn2)라는 메서드를 추가했다.


Listing 2. jQuery hover 메서드
				
// 이 코드는 jQuery가 구현한 hover() 함수를 시연한다. 두 함수를 정의해야 한다.
// 하나는 특정 엘리먼트 위로 마우스가 지나갈 때 동작하는 함수이며,
// 다른 하나는 엘리먼트에서 마우스가 벗어날 때 동작하는 함수다.
// 이 예제에서, 테이블의 각 행은 마우스가 위로 지나갈 때 붉은색 배경으로 변하며,
// 마우스가 벗어날 때 흰색 배경으로 변한다.
$("tr").hover(function(){
   $(this).css("background","#0000ff");
},
function(){
   $(this).css("background","#ffffff");
});

속성

페이지를 상호대화식으로 만드는 요인 중에서 페이지의 특정 영역에서 정보를 얻은 다음에 다른 영역으로 옮기는 기능을 들 수 있다. 이 예는 텍스트 필드에서 정보를 얻어서 테이블에 놓거나 콤보 박스에서 정보를 가져와서 서버로 전송하고 서버에서 받은 정보를 다른 콤보 박스에 넣는 시나리오로 설명이 가능하다. 여기서 핵심은 상호 작용이 페이지에서 정보를 전달한 결과로 나타난다는 사실이다.

특히 페이지에 존재하는 개별 엘리먼트에 정보를 저장하는 다양한 방법이 있다. 아마도 단순한 <p> 태그는 텍스트 필드만큼 많은 정보를 포함하지 않으리라고(이는 참일지도 모르고 거짓일지도 모른다) 상상하기 쉽지만, 이런 정보에 접근하는 다양한 함수가 있다. 페이지 엘리먼트에서 정보를 얻는 방법이 있다면 이런 엘리먼트에 정보를 설정하는 방법도 있으리라는 결론에 이미 도달했을지도 모르겠다. 실제로 각 페이지 엘리먼트는 자료 객체이며, getter/setter 메서드로 캡슐화된 변수를 포함한다. 자바빈 모델과 jQuery에서 사용하는 모델 사이에 나타나는 차이점은 메서드 이름과 몇몇 엘리먼트가 특정 기능에 적합하지 않다는 제약점이다.

이런 메서드를 설명하기 앞서, 페이지 엘리먼트에 저장되는 정보가 무엇인지 살펴보자. <p> 같은 단순한 태그는 정보로 CLASS나 ID만 포함한다. <img> 같은 태그는 "src", "alt", "width", "height" 같은 좀 더 많은 정보를 포함할지도 모른다. 마지막으로 <input type="password"> 같은 복잡한 태그는 "defaultValue", "maxLength", "readOnly", "accessKey" 같은 정보를 포함할지도 모른다.

잠재적인 변수가 다양하기 때문에 jQuery는 이런 정보에 접근하는 일반화된 함수를 제공한다. 이 함수는 attr(name)이며, 특정 페이지 엘리먼트에서 정보에 접근하는 일반적인 방법이다. 동작 원리를 살펴보기 위해 몇 가지 예를 제시한다.


Listing 3. jQuery attr() 함수
				
<img src="/images/space.gif" id="spacer" class="a b c" alt="blank">

// attr() 함수 호출은 다음을 반환한다.
$("#spacer").attr("src"); // "/images/space.gif"를 반환한다.
$("#spacer").attr("alt"); // "blank"를 반환한다.

// 비슷하게 동일한 방식으로 ID에 접근할 수 있다.
$(img).each(function(){
   $(this).attr("id"); // "spacer"를 반환한다.
});

이 함수는 페이지에 상호대화식 기능을 추가해 깔끔한 방식으로 동작하도록 만들 때 아주 유용하다. 사실상, data() 함수가 추가되기 전에는(아래를 참조하자), 일반적으로 필요한 정보를 꽉꽉 눌러서 사용 가능한 변수 중 하나에 밀어 넣었다. 예를 들어, 프레임 두 개를 포함하는 페이지가 있을 때, 첫 번째 프레임은 탭을 보여주고, 하단 프레임은 각 탭 내용을 보여준다면 다음과 같은 방식으로 코드를 작성해야 했다.


Listing 4. attr() 구현
				
<!-- 탭으로 상단 프레임에 나타난다. CSS 파일은 탭 외형을 지정하며,
이렇게 하기 위해 HTML 코드만 필요하다. -->
<td>
   <div class="tab" id="/messages.jsp">Messages</div>
</td>

// 이 코드는 jQuery 섹션에 나타난다. 탭에서 ID를 얻는 방법과
// "messages.jsp" 페이지 내용으로 'content'라는 하단 프레임에
// 이 정보를 설정하는 방법에 주목하자. 

$(".tab").click( function() {
   window.parent.frames['content'].location = $(this).attr("id");
});

각 엘리먼트에서 속성 값을 얻는 이외에 값을 설정할 수도 있다. 이는 엘리먼트의 외형과 행동 양식을 프로그램으로 변경하는 가능성을 열어준다.


Listing 5. attr(str)로 속성 변경하기
				
// 이미지 소스를 변경해서 페이지에 표시되는 이미지 내용을 변경한다.
$("img").attr("src", "myimage.jpg");

// 페이지에 있는 모든 링크를 특정 페이지로 향하도록 변경한다.
$("a").attr("href", "mypage.html");

// 암호 필드에서 maxLength를 열 글자로 변경한다.
$(":password").attr("maxLength", "10");

페이지에 들어있는 form 엘리먼트에는 엘리먼트에 붙어 있는 값을 얻기 위해 호출할 수 있는 특수한 함수가 존재한다. 이는 폼 입력이나 유효성 검증과 관련한 작업 과정에 특히 편하다. form 엘리먼트로 상호대화식 웹 사이트를 구축할 때 이런 함수를 자주 사용할 것이다.


Listing 6. form 엘리먼트 val() 함수
				
// 텍스트 필드에 포함된 텍스트를 얻어서 공백인지 점검한다.
$(":textfield").each(function(){
   // val() 함수를 활용해 텍스트 필드 내부에 텍스트를 얻는다.
   if ($(this).val() == "")
       $(this).next().text("Error");
});

// 새로운 암호 페이지에서 양쪽이 동일한지 확인하기 위해 암호를 비교한다.
if ($("#newPassword").val() != $("#confirmPass").val())
   $("#newPassword").next().text("Error");

또한 특정 태그 내부에 포함된 정보를 얻는 함수도 있다. 이런 함수를 어떻게 활용할까? 아마도 특정 <td> 태그에 들어있는 모든 정보를 얻어 대체하거나, <p> 내부에 들어있는 모든 텍스트를 소문자로 바꾸기를 원할지도 모르겠다. 이런 속성을 얻는 두 가지 독자적인 방법이 있는데, 이런 과정에서 attr() 함수를 사용하지는 못한다. 다른 속성 함수와 마찬가지로, 이런 함수에는 대응하는 setter 함수가 존재한다. 첫 번째 함수는 html() 함수로 특정 태그의 모든 innerHTML을 반환한다. 다른 함수는 text() 태그로 특정 태그 내부에 포함된 모든 텍스트를 반환한다. html() 함수는 HTML 태그를 포함한 텍스트를 반환하는 반면에, text() 태그는 HTML 태그를 벗겨내며 내부 텍스트만 반환한다. 다음 예제를 보면 차이점을 알아챌 수 있다.


Listing 7. html() 대 text()
				
// 이 예제는 모든 <td> 태그를 검사해서 값이 공백이면 내부에 "-"를 넣는다.
$("td").each(function(){
   // 테이블 셀에 들어있는 텍스트를 점검한다.
   if ($(this).text() == "")
       $(this).text("-");
});

// 이 예제는 모든 문단의 텍스트를 소문자로 바꾼다.
$("p").each(function(){
   var oldText = $(this).text();
   var newText = oldText.toLowerCase();
   $(this).text(newText);
});

<-- 이 예제는 text()와 html() 사이에 나타나는 차이점을 보여준다. -->
<div id="sample"><b>This is the example</b></div>

$("#sample").html(); // "<b>This is the example</b>"을 반환한다.
$("#sample").text(); // "This is an example"을 반환한다.

마지막으로 최근에 속성과 관련해서 jQuery 라이브러리에 추가된 함수는 data()다. 이 함수는 jQuery UI 프로젝트에서 나왔고, 최근에 jQuery 프로젝트에 통합되었다. 원래부터 UI 프로젝트 개발자들은 특정 페이지 엘리먼트를 위해 사용 가능한 속성을 편법으로 얻기를 원하지 않았으며, 필요한 만큼 저장이 가능하도록 속성을 만들어내는 방식을 원했다. 직전에 소개하는 탭 예제로 돌아가보자. DIV의 ID 내부에 있는 링크를 편법으로 찾아내었는데 이는 이상적인 방식이 아니다. 하지만 jQuery 직전 버전의 제약 때문에 이런 방식이 유일한 대안이었다. data() 함수를 포함하면서부터 jQuery는 이런 문제를 해결하는 좀 더 우아한 해법을 제공한다. data() 함수를 각 페이지 엘리먼트에 포함된 내부 사전에 접근하는 수단으로 생각해보자. 사전은 키-값 쌍을 모아놓은 집합이다. 이는 개발자가 페이지 엘리먼트에 원하는 전용 속성을 만든 다음에 이 속성에 값을 붙이도록 허용한다. 궁극적으로, 이런 방식은 좀 더 쉬운 코드를 만들어내도록 이끌며, 프로젝트가 점점 더 커짐에 따라 유지보수도 점점 더 쉬워진다. 위에서 소개한 예를 새로운 data() 함수를 써서 다시 한번 구현해보자.


Listing 8. 새로운 data() 함수
				
// 위에서 수행했던 방식처럼 div를 생성하지만 구체적인 정보를 활용하지 않는다.
// 이런 식으로 jQuery 코드에서 일반적인 HTML 레이아웃을 만들고 수정할 수 있다.

<td>
   <div class="tab"></div>
</td>

// 이제 jQuery 코드에서 각 탭을 수정한다.

$(".tab").eq(0).text("Messages");
$(".tab").eq(0).data("link", "messages.jsp");
$(".tab").click(function(){
   window.parent.frames['content'].location = $(this).data("link");
});

// 한 걸음 더 나가서, 자바 배열을 통해 외부 속성 파일에서 이런 정보를 얻어보자.
// JSP 페이지에 있는 코드다.

<%
  // 탭 이름을 포함하는 배열
  String[] tabNames;
  // 탭 링크를 포함하는 배열
  String[] links;

  for (int i=0; i<tabNames.length; i++) {
%>
  $(".tab").eq(<%=i%>).text("<%=tabNames[i]%>");
  $(".tab").eq(<%=i%>).data("link", "<%=links[i] %>");
<% } %>

$(".tab").click(function(){
   window.parent.frames['content'].location = $(this).data("link");
});

CSS 조작

이 기사에서 소개할 마지막 내용은 스타일 시트를 조작하거나 페이지를 새로 고치지 않고서 CSS를 조작하는 방법이다. 이는 색상, 글꼴 등 단순한 화면 구성 요소를 변경하는 방법으로 페이지에 기본적인 효과를 추가하는 능력을 부여한다. jQuery에서 CSS 부문은 전반적인 라이브러리 탄생을 이끌도록 영감을 불러일으켰다. 웹 페이지에서 CSS 프로그래밍을 쉽게 만들기 위한 목표로 시작했으며, 살펴본 바와 같이 프로젝트는 무럭무럭 자라났다. 여전히 원래 프로젝트 의도를 따르기에, jQuery는 CSS로 프로그래밍 작업을 손쉽게 하는 방법을 제공한다. 하지만 jQuery가 제공하는 CSS 조작을 위한 전통적인 함수는 실제로 오늘날 웹 환경에 적합하지 않으므로, (jQuery에서) 대신 사용할 다른 함수를 제시하겠다.

웹 페이지에서 CSS를 조작하기 위한 기본적인 함수 두 가지를 사용하면 문자열로 단일 속성을 전달하거나 문자열 배열로 한번에 속성을 전달할 수 있다. 두 함수 모두 똑같은 작업을 수행하며 웹 페이지에서 CSS를 쉽게 변경할 수 있다.


Listing 9. css() 함수
				
// 모든 div 배경을 붉은색으로 변경한다.
$("div").css("backgroundColor", "#ff0000");
// 또는
$("div").css("backgroundColor", "red");
// 또는
$("div").css({backgroundColor: "#ff0000"}); // 괄호나 따옴표 쌍을 주의한다.

이런 함수는 아주 직관적이며 금방 익힐 수 있다. 하지만 웹 페이지 디자인 분야에서 현재 추세를 고려할 때 문제점도 발견할 수 있다. 일반적인 웹 페이지는 페이지에서 스타일을 제거한 다음에 코드 섹션이나 외부 파일에 스타일시트로 놓아둔다. 피할 수만 있다면 스타일 코드를 자바스크립트 코드에 넣어두기를 원하지 않을 것이다. 이렇게 하면 나중에 사이트 외형 변경이 어려워진다.

다행스럽게, 필요한 분리 기능을 제공하는 대체 함수가 존재한다. 이 함수를 사용해도 여전히 CSS 조작이 쉽고 직관적이다. 이 함수는 페이지 엘리먼트에서 클래스를 추가하고 제거하는 기능을 제공한다. 외부 스타일 시트에서 이런 클래스에 스타일을 적용하는 방법으로 스타일/자료/사건을 분리할 수 있으며, 이는 복잡한 페이지에서 아주 중요한 특성이 된다. 몇 가지 예제를 살펴보자.


Listing 10. 바람직한 CSS 조작: addClass()와 removeClass()
				
// "input_error" 클래스를 추가해서 검증에 실패한 폼 엘리먼트에 적용한다.
// "input_error" 클래스를 외부 CSS 파일에 정의해 붉은 색 테두리와 붉은 색 텍스트로
// 지정한다.

$(":textfield").each(function(){
   if ($(this).val() == "")
   {
       $(this).next().text("Error");
       // 이렇게 하면 필드 테두리와 텍스트가 붉은색으로 변한다.
       $(this).addClass("input_error");
   }
   // 텍스트 필드에 이미 클래스를 적용했는지 검사한다.
   else if ($(this).hasClass("input_error"))
   {
       $(this).next().text("");
       // 클래스를 삭제해 정상적인 테두리/텍스트로 복원한다.
       $(this).removeClass("input_error");
   }
});

예제를 보면 알겠지만, CSS 조율을 위한 외부 스타일시트에 정의된 클래스 참조 기법은 웹 페이지에서 CSS를 조작하는 바람직한 방식이다. 이렇게 하면 웹 사이트 작성자가 스타일시트 하나만 바꾸는 방법으로 전체 사이트에서 오류 메시지 처리 방법을 바꿀 수 있다. 직전에 소개한 css() 호출 방법을 사용할 경우 모든 코드 인스턴스를 쫓아다니며 변경해야 한다. css() 메서드는 사용하기도 쉽고 직관적임에도 불구하고 대규모 웹 응용에는 적합한 해법이 아니며 addClass()removeClass() 메서드를 사용함으로써 이를 회피해야 한다.

여기서 배운 모든 내용을 하나로 합치기

여기서 배운 모든 내용을 하나로 합치기 위해 다시 한번 예제로 돌아가자. RIA를 만들기 위한 상호대화식 웹 응용은 사용자에게 전자편지 기능을 제공하는 데스크톱 응용으로 작업하는 느낌을 준다. 여기서는 사건, 속성, CSS 모듈을 사용해 웹 메일 응용이 마우스 클릭과 더블 클릭을 다루는 방법을 정의한다. 아래 제시한 스크린샷에서 기대했던 행동 양식을 살펴볼 수 있다. 사용자가 테이블 행에 클릭하면 현재 선택한 행의 색상이 바뀐다. 사용자가 메시지를 더블 클릭하면 메시지를 읽는다. 하지만 또한 사용자가 새로운 메시지를 읽으면 행의 배경색을 바꿔 메시지를 읽었다고 표시해준다.


그림 1. 행을 클릭하기
행을 클릭하기

그림 2. 행을 더블 클릭하기
행을 더블 클릭하기

Listing 11. 여기서 배운 모든 내용을 하나로 합치기
				

// 먼저 테이블에 행을 추가한다. 각 행은 "messageRow" 클래스 멤버다.
// 각 행에 ID를 부여하고, 이 ID는 자바 자료 객체에서 얻은 메시지 번호로 지정한다.
// JSP 파일에서 for 루프로 이를 지정한다.

<%
   for (int i=0; i<messages.size(); i++)
   {
      MessageData message = messages.get(i);
%>
      <tr class="messageRow" id="<%=message.id %>">
      
// 테이블을 만들었다면, jQuery 코드를 사용해 마우스 클릭과 더블 클릭을 잡아내도록
// 정의한다.

// click() 함수를 사용해서 행에 클릭하는 행위를 감지한다.
// 다음에 css() 함수를 사용해 CSS를 직접 조작하는 대신에 use addClass()와
// removeClass()를 사용하는 방식에 주목하자. 이는 jQuery 코드 변경없이 스타일
// 시트를 변경하도록 허용한다.

$(".messageRow").click(function() {
     $(".messageRow").removeClass("message_selected");
     $(this).addClass("message_selected");
});

// 이제 테이블 행을 더블 클릭할 때를 잡아낸다. post() 함수의 Ajax 메서드는 무시한다.
// 다음 기사에서 다룰 계획이다. 여기서 dbclick() 함수를 사용해 더블 클릭을
// 잡아낸다. Ajax 호출에 주목하자. 더블 클릭한 테이블 행의 ID를 가져온다.
// 이렇게 가져온 ID를 서버에 날려 서버에서 메시지 정보를 얻는 데 사용한다.
// JSP 코드에서 메시지 번호를 정의했으므로 ID는 메시지 번호를 포함한다.

$(".messageRow").dblclick(function() {
     if ($(this).hasClass("mail_unread"))
     {
         $(this).removeClass("mail_unread");
     }
     $.post("<%=HtmlServlet.READ_MESSAGE%>.do", 
     {
            messageId: $(this).attr("id"),
            view: "<%=view %>"}, 
            function(data){
            // Ajax 관련 코드를 여기에 넣는다.
            });
     });
});

결론

jQuery와 같은 자바스크립트 라이브러리는 데스크톱에서 브라우저로 응용 프로그램을 이식함에 따라 점점 더 중요해진다. 이런 응용은 점점 더 복잡해지므로 웹 응용 프로젝트에서 jQuery와 같은 튼튼한 교차 브라우저 해법을 필수로 요구한다. jQuery는 다른 자바스크립트 라이브러리와 격차를 벌리기 시작했으며, 필요한 모든 작업을 수행하는 능력과 함께 손쉬운 개발 특성 때문에 많은 개발자들이 jQuery를 핵심 라이브러리로 선택하고 있다.

연재물 두 번째 기사에서 웹 페이지에서 일어나는 상호 작용을 살펴봄으로써 jQuery 지식을 확장했다. 또한 (서버에서 정보를 가져오지 않고서) 클라이언트에서 기초적인 상호 작용을 달성하는 방법을 살펴보았다. 사건 모듈을 살펴보기 시작했는데, 페이지 엘리먼트가 마우스, 키보드, 초점을 비롯한 다양한 상호 작용에 반응하는 방법을 정의했다. 이벤트는 웹 페이지에서 상호 작용을 일으키는 거대한 드라이버라는 사실을 확인했으며, 활용을 위해 반드시 form 엘리먼트일 필요가 없다는 사실도 배웠다. 그러고 나서 속성 설명으로 넘어가서, 페이지 엘리먼트에서 속성을 적절히 가져오고 설정하는 방법을 배웠다. 일반적인 attr() 함수를 사용해 모든 엘리먼트에 일반적인 접근 방법이 있다는 사실과 함께 form 엘리먼트 값을 얻기 위한 특별한 함수가 존재한다는 사실도 살펴보았다. 또한 jQuery에서 data() 함수가 새롭게 추가되었기에, 프로그래머가 원하는 어떤 속성도 만들 수 있도록 각 페이지에 속한 엘리먼트에 해시 지도를 포함할 수 있다는 사실도 배웠다. 마지막으로 페이지를 새로 고치지 않고서도 페이지 엘리먼트의 CSS를 변경하는 방법도 살펴보았다. css() 함수가 쉽고 직관적이기는 하지만, addClass()removeClass()를 사용해 이런 함수를 대체하는 편이 바람직하다는 사실도 배웠다. css() 함수는 jQuery 코드에서 페이지 스타일을 독립적으로 유지하는 기능이 없기 때문이다.

이 기사에서 마지막 부분은 세 가지 모듈을 결합해 마우스 상호 작용을 제공하는 웹 메일 응용 예제를 설명한다. 이 예제는 클릭한 행을 강조하는 행위와 더블 클릭해서 읽은 메시지를 표시하기 위한 행위를 구분하며, 메시지에 밀접한 자료를 서버에 요청하도록 Ajax 호출을 통해 프로세스에서 서버 쪽으로 메시지 번호를 전달하는 기능을 구현한다.

연재물에 속한 다음 기사에서 jQuery에서 Ajax 기능을 좀 더 깊숙히 다루며, Ajax 활용 과정에서 나타나는 복잡도를 일반적으로 사용하는 자바스크립트 호출만큼이나 단순하게 만드는 방법을 살펴보겠다. 추가로 jQuery에 들어있는 효과 모듈을 살펴볼 것이다. 이 모듈은 사용자에게 근사한 시각 효과와 추가적인 상호 작용을 강화하는 기능을 선사한다. 다음 기사에서 마지막으로 다룰 내용은 데모용 웹 메일 응용 정리와 jQuery에서 얻은 교훈이다. 여러분도 jQuery 라이브러리를 독자적인 웹 응용에 추가해서 사용하리라 믿는다.

참고자료

교육

토론


필자소개

Mike Abernethy

10년에 걸친 기술 경험을 통해 Michael Abernethy는 광범위한 기술을 토대로 광범위한 클라이언트와 작업해 왔다. 현재 경매 소프트웨어 회사인 Optimal Auctions에서 제품 개발 관리자로 일한다. Abernethy는 요즘 RIA(Rich Internet Applications)에 초점을 맞춰 복잡함과 단순함을 동시에 추구하고 있다. 컴퓨터 앞에 앉아 있지 않을 때는 양서를 끼고 멕시코 해변가에서 여유를 즐긴다.