jQuery 셀렉터 : 필터 사용하기

필자의 잡담~

제가 jQuery 강좌에서 특히나 셀렉터 부분을 집중적으로 이렇듯 자세하게 설명하는 이유는 현재 출판된 서적이나 아티클들에서 이러한 부분을 조목조목 정리한 문서를 찾아보기가 쉽지 않아서 입니다(물론, 제가 잘 찾지 못했을 수도 있습니다).

더불어, 셀렉터(selector)가 jQuery의 화려한 기능들을 다루기에 앞서 반드시 알아두어야 하는 궁극의 기본기이기에 그렇기도 합니다.
jQuery 셀렉터 : 기본 필터

기본적인 셀렉터에 더하여, jQuery는 다양한 셀렉터 필터들도 제공을 합니다. 바로 앞에서 다루었던 어트리뷰트 셀렉터의 경우도 필터의 한 예입니다만, 어트리뷰트 셀렉터는 지금부터 다룰 필터들과는 표현식이 약간 달라서 기본 셀렉터와 함께 다루었습니다.

필터는 말 그대로 걸러내는 역할을 합니다. jQuery는 위치를 기반으로 필터링 하거나, 하위 자식들을 필터링할 수 있게 한다거나, 컨텐트를 기반으로 필터링하는 등 다양한 방식으로 원하는 요소들을 필터링하여 선택할 수 있게 합니다. 그리고, 대부분의 필터는 : 을 시작문자로 사용하는 단어들입니다. 이러한 필터는 일반적으로 기본 셀렉터에 덧붙여 사용하곤 하지만, 단독으로 사용할 수도 있습니다. 그러면, 우선 가장 일반적인 필터들부터 차례대로 살펴보도록 할까요?

< 기본 필터 >

:first 선택된 개체들 중 첫 번째 요소와 일치합니다.
:last 선택된 개체들 중 마지막 요소와 일치합니다
:not(selector) 괄호에 주어진 셀렉터와 일치되는 모든 요소를 제외합니다.
:even 짝수 요소들과 일치합니다(0부터 시작)
:odd 홀수 요소들과 일치합니다(0부터 시작)
:eq(index) 인덱스에 해당하는 단일 요소와 일치합니다
:gt(index) 주어진 인덱스보다 높은 인덱스를 갖는 모든 요소와 일치합니다
:lt(index) 주어진 인덱스보다 낮은 인덱스를 갖는 모든 요소와 일치합니다
:header 모든 헤더 요소들(h1, h2, h3 등)과 일치합니다
:animated 현재 애니메이션이 동작중인 모든 요소와 일치합니다

각각의 필터는 셀렉터로서 독립적으로 사용될 수도 있고, 다른 셀렉터와 함께 사용할 수도 있습니다. 더불어, 여러 필터를 이어서 사용할 수도 있죠. 예를 들어 다음과 같이 말이죠.

tr:odd
tr:gt(4)
tr:last
:header:eq(1)

각각의 셀렉터가 의미하는 바는 쉽게 이해하실 수 있을 것입니다.

첫 번째 셀렉터인 tr:odd는 현재 문서에 존재하는 모든 tr 중 홀 수번째 열들만을 선택하는 것이며, 두 번째 셀렉터인 tr:gt(4)는 문서에 존재하는 모든 tr 중 그 인덱스가 4 이상인 모든 열들을 선택하는 것이고요. 세 번째 셀렉터인 tr:last는 모든 tr 중 가장 마지막 tr을 선택하는 셀렉터입니다. 그리고, 마지막 셀렉터는 문서에 존재하는 헤더들 중에서 인덱스가 1번째인 헤더를 선택하는 셀렉터이지요.

주의할 점은 여기서의 인덱스는 0부터 시작이라는 것입니다. 고로, 첫번째로 나오는 tr은 인덱스 0을 가지므로, 홀수 열이 아니라 짝수열이라는 것을 기억하셔야 합니다.

해서, 다시 정리하자면,

tr:odd 문서에 나오는 모든 tr 중 홀수번째 tr만을 선택합니다. 그런데, 인덱스는 0부터 시작하므로, 사실, 제일 처음 나오는 tr은 짝수 열로 인식된다는 부분에 주의하세요.
tr:gt(4) 문서에 나오는 tr 중 5번째(인덱스 4) 후에 나오는 모든 tr 즉, 6번째 tr 부터 모든 tr을 선택합니다.
tr:last 문서에 나오는 모든 tr 중 가장 마지막에 존재하는 tr만을 선택합니다.
:header:eq(1) 현재 문서에 나오는 모든 헤더(h1, h2, h3 등) 중에서 인덱스 위치가 1인 헤더 즉, 눈에 보이기에 두 번째로 나오는 헤더를 선택합니다.

필터 앞에 아무것도 지정되지 않으면, 암시적으로 *이 지정된 것으로 인식됩니다. 즉, 이는 *:header:eq(1)와 동일한 표현으로 인식된다는 것이며, 페이지에 존재하는 모든 요소 중에서 헤더를 찾게 됩니다.

라는 것입니다. 하하. 설명이 쉬우니 머리에 쏙쏙 들어오죠? 더욱 이해하기 쉽도록 예제를 통해서 확인을 해보도록 합시다.

Filter01.htm

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    
<title></title>
    
<script src="jquery-1.3.2.min.js" type="text/javascript"></script>
    
<script type="text/javascript">
        $(
document).ready(
            
function() {
                $(
"tr:odd").css("background""#efefef");
                
$("tr:gt(4)").css("background""silver");
                
$("tr:last").css("background""yellow");
                
                
$(":header:eq(0)").css("font-weight""bold").css("color""blue");
            
});
    </
script>
    
<style type="text/css">
        
* { font-size:12px; font-family돋움 }
        
.nameTable { background: white; border-collapse:collapse }
    </
style>
</head>
<body>
    
<h3>수학 시험 점수</h3>
    
<table class="nameTable" border="1" cellpadding="10">
        
<tr><td width="100">name</td><td width="100">value</td></tr>
        
<tr><td>Taeyo</td><td>80</td></tr>
        
<tr><td>Dragon</td><td>98</td></tr>
        
<tr><td>Eric</td><td>85</td></tr>
        
<tr><td>Queeny</td><td>96</td></tr>
        
<tr><td>Youngsun</td><td>88</td></tr>
        
<tr><td>kobukii</td><td>90</td></tr>
        
<tr><td>Mr.Net</td><td>92</td></tr>
    
</table>
</body>
</html>

보시디시피, 문서에는 총 8개의 tr이 존재하고 있고요. 각각의 셀렉터는 그러한 tr을 대상으로 해서 스타일을 매기고 있습니다. css() 라는 메서드는 이전 강좌에서도 다룬 적이 있지만, 대상 개체에 css 스타일을 적용하는 메서드인거 기억하시죠?

예제는 모든 홀수번째 tr(tr:odd)에게는 #efefef 배경색(아주 연한 회색)을 적용하고 있고요. 인덱스 번호 4 이후의 모든 tr들(즉, 6번째 tr 부터)에 대해서는 silver 배경색을 적용하고 있습니다. 그리고, 가장 마지막 tr(tr:last)에 대해서는 yellow 배경색을 주고 있고요. 더불어, 문서상에서 첫 번째로 나오는 헤더(:header:eq(0))에는 굵고 파란색의 폰트를 설정하고 있습니다.

해서, 결과 화면은 다음과 같이 나타나게 되는 것이죠.

매우 간단한 예제였지만, 이 예제는 마지막 셀렉터에 스타일을 주는 부분에서 재미있는 것이 하나 있는데요.

$(":header:eq(0)").css("font-weight""bold").css("color""blue");

라는 구문을 보시면, 셀렉터 대상에 대해서 css()라는 메서드를 연달아 사용하는 것을 볼 수 있죠? 이를 메서드 체인이라고 하는데요. jQuery가 제공하는 모든 메서드는 그 반환값(return value)이 효과가 반영된 jQuery 개체이기 때문에 이런 식으로 메서드를 이어서 사용할 수가 있습니다. 다시 말해서, 저 표현은

var jQ = $(":header:eq(0)")
jQ = jQ.css("font-weight", "bold");
jQ = jQ.css("color", "blue");

와 동일하다 할 수 있다는 것이죠. 하지만, 이러한 방식은 직관적이기는 하지만 소스가 길어지는 단점이 있기에, 일반적으로는 메서드 체인으로 작성하곤 합니다.

물론, 메서드 체인으로 작성할 경우에, 체인이 너무 길어지게 되면 오히려 소스가 더 복잡해 보일 수 있기에 부담스러워 하시는 분들도 있는데요. 자바스크립트는 줄바꿈을 인식하지 않기 때문에 다음과 같이 줄을 바꿔가면서 메서드 체인을 작성할 수 있습니다. 그리고, 대부분의 jQuery 개발자들도 다음과 같은 메서드 체인 방식을 즐겨 사용한답니다.

$(":header:eq(0)")
    .css("font-weight", "bold")
    .css("font-size", "12px")
    .css("color", "blue");

어때요? 보기 편하죠? 지금은 가벼운 예제들이기에 이러한 메서드 체인은 자주 볼일이 없지만, 이후의 강좌에서는 다양한 기능을 다루면서 메서드 체인이 마구 늘어나게 될 것입니다.

위의 메서드 체인에서는 css() 메서드를 3번 연속 사용하고 있는데요. 이는 단지 메서드 체인의 예를 든 것임을 기억하세요. 실제로 저렇게 여러 스타일을 매기고자 하는 경우에는, css 메서드를 반복해서 사용하지 않고요. 스타일시트 파일에 필요한 css 클래스를 하나 만들어 두고, jQuery의 addClass() 메서드를 사용하여 스타일을 한번에 지정하곤 합니다. 이에 대해서는 뒤에서 다룰 예정입니다.

참 재미있군요.

물론, "별로 재미없는데요"라고 말하시는 분이 있을 수도 있습니다만, 이 기능은 실제 jQuery가 제공하는 막강한 기능의 10%도 안되는 것이라서 아직까지는 감동이 적을 수도 있습니다. 셀렉터를 다루는 것은 jQuery의 멋진 기능을 다루기 위한 기본기라는 것을 기억하셔야 합니다. 지금은 드리볼을 배우는 단계입니다. 아직은 슛을 쏘기에는 이르다는 것이죠.

jQuery 셀렉터 : 컨텐트 필터와 자식 필터

이상 기본 필터에 대해서 알아봤는데요. 이 외에도 몇 개 안되지만 컨텐트 필터와 자식 필터라는 것이 또한 존재합니다. 이 또한 자주 쓰일만한 것이기에 마저 알아보도록 하죠.

먼저 컨텐트 필터입니다. 현재 버전에서는 꼴랑 다음과 같이 4개의 필터가 존재합니다.

< 컨텐트 필터 >

:contains(text) 지정한 텍스트를 포함하는 요소들과 일치됩니다
:empty 자식을 가지지 않는 모든 요소와 일치됩니다. 더불어, 내부 텍스트를 가지지 않는 요소들도 이에 해당됩니다.
:has(selector) 지정된 셀렉터에 해당하는 요소를 갖는 모든 요소들과 일치됩니다.
:parent 부모인 모든 요소들과 일치됩니다. 자식 요소를 갖는 요소 뿐만 아니라 텍스트를 갖는 요소들이 이에 해당됩니다.

별거 아닌 것처럼 보이는 이 필터들, 막상 알고나면, 각각의 필터들이 상당히 유용합니다.

개인적으로는 :empty 필터가 상당히 유용했는데요. 예를 들면, 그리드 출력을 하는 경우에, 값이 누락되어 있는 셀들(td)을 찾아서 그 셀들만 배경색을 회색으로 처리한다거나 할 때는 완전 딱입니다. 물론, contains() 필터와 :has() 필터도 유용하긴 마찬가지 입니다.

다음과 같은 셀렉터를 한번 살펴볼까요?

b:contains('j')
div:has('ul')
table.nameTable td:empty
.nameTable td:contains('F')
table.nameTable tr:eq(0)

첫 번째 셀렉터는 "j"라는 단어를 포함하는 모든 b 요소들을 선택합니다.
두 번째 셀렉터는 모든 div 요소들 중에 ul 요소를 가지고 있는 div 만을 선택합니다.
세 번째 셀렉터는 nameTable이라는 css 클래스가 지정된 table들 중에서 자식 요소인 td 내부에 텍스트 값이 없는(또는 자식요소가 없는) 모든 td를 선택합니다.
네 번째 셀렉터는 nameTable이라는 css 클래스가 지정된 요소들 중에서 그 내부의 td가 텍스트로 "F"란 단어를 포함하고 있는 모든 td를 선택합니다.

마지막 셀렉터는 이미 이전에 다루었던 것이라 굳이 설명할 필요가 없어보이긴 하지만 복습의 차원에서 설명하자면, nameTable이라는 css 클래스가 지정된 table 내의 tr 중에서 첫번째 tr을 선택합니다.

그다지 어렵지 않게 구분이 가능하시죠?

그리고, 기왕 이야기를 하는 김에요. 사실은 이전 강좌에서 이야기할까 하다가 접었던 짧은 이야기를 하나 보태볼까 하는데요. 복습의 차원에서 한번 읽어봐 주시겠어요?

만일, 문서 내에 table 요소가 한 개만 존재하고, 그 table에 nameTable 이라는 css 클래스가 적용이 되었다면, 다음의 셀렉터는 모두 같은 것을 선택한다는 것!

$("table.nameTable tr")
$(".nameTable tr")
$("table tr")
$("tr")

네. 당연한 이야기입니다. 그렇죠? 그래요. 기본 셀렉터의 다양한 형태를 복습의 차원에서 한번 같이 살펴본 것 뿐입니다. 굳이 이러한 이야기를 꺼낸 것은 셀렉터를 처음 접할 경우에는 셀렉터를 어떻게 작성하는 것이 좋은지에 대해 자꾸 걱정하는 분들이 있어서요. 셀렉터는 문서 내에서 원하는 요소를 명확히 찾아낼 수 있는 직관적인 구문이면 뭐든지 오케이입니다. 특별히 어떤 구문이 더 좋다라는 식의 정해진 룰은 없습니다. 물론, 자꾸 사용하시다보면 자신만의 패턴이 생기긴 할 겁니다~(저의 경우는 가급적 구문을 상세하게 작성하는 것을 권합니다)

그러면, 이제 예제를 통해서 컨텐트 필터들의 사용 예를 한번 살펴볼까요?

Filter02.htm

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    
<title></title>
    
<script src="jquery-1.3.2.min.js" type="text/javascript"></script>
    
<script type="text/javascript">
        $(
document).ready(
            
function() {
                $(
"b:contains('j')").css("background""yellow");
                
$("div:has('ul')").css("border""solid 1px green");

                
$("table.nameTable td:empty").css("background""#dddddd");
                
$(".nameTable td:contains('F')").parent().css("background""pink");
                
$("table.nameTable tr:eq(0)").css("background""lightblue");
            
});
    </
script>
    
<style type="text/css">
        
* { font-size:12px; font-family돋움 }
        
.nameTable { background: white; border-collapse:collapse }
    </
style>
</head>
<body>
    
<h3>jQuery란?</h3>
    
<div>
        
<b>jQuery</b>는 가볍고 빠르며, 간결한 오픈소스 스크립트 라이브러리입니다. 
        이를 이용하면 Rich 웹 UI를 개발하는 데 도움이 되는 다양한 기능들 즉,
        
<b>HTML 문서 트래버스</b><b>이벤트 처리</b><b>애니메이션</b><b>Ajax 상호작용
        </b>등을 지원하여 빠르고 견고하게 리치 웹 애플리케이션 개발을 할 수 있도록 지원합니다.
    
</div>
    
<br />
    <
div>
        이러한
<b>jQuery</b>의 기능적인 특징은 다음과 같습니다
    
</div>
    
<br />
    <
div>
        
<ul>
            
<li>막강한 CSS 셀렉터</li>
            
<li>크로스 브라우저 지원</li>
            
<li>메서드 체인</li>
            
<li>Ajax 지원</li>
            
<li>풍부한 플러그 인 지원</li>
        
</ul>
    
</div>
    
<br />
    <
table class="nameTable" border="1" cellpadding="3">
        
<tr><td width="100">이름</td><td width="100">성별</td><td width="100">기타 정보</td></tr>
        
<tr><td>Taeyo</td><td>M</td><td>...</td></tr>
        
<tr><td>Dragon</td><td>M</td><td>...</td></tr>
        
<tr><td>Eric</td><td>M</td><td>...</td></tr>
        
<tr><td>Queeny</td><td>F</td><td>...</td></tr>
        
<tr><td>Youngsun</td><td></td><td>...</td></tr>
        
<tr><td>Hera</td><td>M</td><td>...</td></tr>
        
<tr><td>Secret</td><td>F</td><td>...</td></tr>
    
</table>
</body>
</html>

셀렉터들이 어떤 요소를 선택하고, 어떻게 동작할지는 소스를 보시면 이해가 되실 것입니다. 예제에서 사용한 셀렉터는 이미 예제에 앞서 설명을 드린 셀렉터 그대로이니까요. 다만, 4번째 구문인 다음 구문에서는 parent()라는 처음 보는 메서드가 하나 사용된 것을 보실 수 있을 겁니다.

$(".nameTable td:contains('F')").parent().css("background", "pink");

parent()라는 메서드는 말 그대로 현재 셀렉터에 의해 선택된 개체 집합의 바로 위 부모 개체를 반환하는 메서드입니다. 고로, 이 구문은 .nameTable 이라는 css 클래스를 갖는 개체의 td들 중에서 "F"라는 텍스트를 포함하는 모든 td를 찾아낸 다음(여기까지가 셀렉터), 그의 부모인 tr 개체를 얻어내서( parent 메서드), 그의 배경색을 핑크빛으로 물들이는 것입니다.

그리고, 결과 화면은 이미 여러분이 셀렉터를 해독하여 예상하고 있던 것과 마찬가지로 다음과 같이 나타나게 될 것입니다.

예상대로, b 요소 중 "j"라는 단어가 포함된 것들은 노란 배경색으로 출력되고 있으며, div 요소들 중에서 ul이라는 자식 요소를 가진 개체는 녹색 테두리로 나타나고 있습니다. 또한, 테이블에서 내용이 없는 td는 연한 회색으로 채워져 있으며, td 안의 텍스트가 "F"라는 글자를 포함하고 있으면 그의 부모인 tr이 핑크색으로 출력되는 것을 볼 수 있습니다. 마지막으로, 가장 첫 번째 tr은 연한 파란색으로 출력되고 있고요.

컨텐트 필터는 이처럼 요소의 컨텐트와 관련하여 필터링을 하는데 사용할 수 있는 기능입니다.

컨텐트 필터 외에 또 다른 필터로 자식 필터라는 것도 있습니다. 자식 필터는 말 그대로 현재 요소의 자식들에 대한 필터를 할 수 있는 기능을 제공하는데요. 현재 버전의 jQuery(1.3.2)에서는 다음과 같이 4개의 자식 필터가 제공됩니다.

< 자식 필터 >

:nth-child(index/even/odd) 자식 중 index로 지정된 위치의 요소들과 일치되거나, even, odd에 해당하는 자식들과 일치됩니다. 단, 여기서의 index는 1부터 시작합니다.
:first-child 첫 번째 자식인 모든 요소와 일치됩니다.
:last-child 마지막 자식인 모든 요소와 일치됩니다.
:only-child 자신이 부모 요소의 유일한 자식인 모든 요소와 일치됩니다

처음 이 필터를 접할 경우에는 이전에 다루었던 기본 필터 중 :first, :last와 유사한 필터가 아닐까 하고 생각할 수 있는데요. 사실 이들은 기존의 필터와 상당한 차이가 있습니다.

:first, :last 필터가 단일 요소를 선택하는 반면, 자식 필터들은 단일 요소가 아닌 해당 요소들의 집합을 선택한다는 것이 차이입니다. 예를 들어, 다음 두 셀렉터의 차이를 한번 생각해 볼까요?

td:first
td:first-child

얼핏 보기에는 같은 요소를 선택할 것처럼 보이는 이 둘은 확실한 차이를 보입니다. 즉,

td:first는 현재 테이블 안에서 첫 번째로 나오는 td 하나 만을 선택하는 반면, td:first-child는 현재 테이블 안에서 나오는 첫 번째 수준의 td들을 모두 선택한다는 것이죠. 말로 이해가 잘 안 가시면 다음 그림을 한번 보도록 하세요.

차이가 느껴지시죠?

:nth-child라는 필터도 동작 방식은 동일합니다만, 인덱스를 지정할 수 있거나, even 이나 odd와 같은 값을 지정하여, 짝수나 홀수 번째 그룹이 선택되도록 할 수 있습니다. 심지어는 Xn+Y와 같은 수식을 사용해서 특정 규칙에 따라 선택할 수도 있습니다. 예를 들어, td:nth-child(3n)과 같이 작성하게 되면, 이는 3의 배수에 해당하는 위치의 td 그룹이 선택될 것이며, td:nth-child(2n+1)과 같이 작성하게 되면, 2의 배수에 1을 더한 값에 해당하는 위치의 td 그룹이 선택될 것입니다. 수식에서의 n은 0부터 계산되기에, 3n은 0,3,6,9 .. 에 해당하는 그룹이 되며, 2n+1은 1,3,5,7… 에 해당하는 인덱스 그룹이 선택될 것입니다.

다만, 여기서의 인덱스는 0부터 시작하는 것이 아니라 1부터라는 것에 유념하셔야 합니다. 요 부분이 살짝 짜증(?) 나는 부분이긴 한데요. 앞서 다룬 기본 필터(:even, :odd, :eq(index), :gt(index) 등)에서는 인덱스가 0부터 시작했으나, 자식 필터인 :nth-child에서의 인덱스는 1부터 적용된다는 것이죠.

즉, :first-child와 동일한 것은 :nth-child(1)이지, :nth-child(0)이 아니라는 것입니다. 자식 필터에서 :nth-child(0)은 그 어떤 것과도 일치되지 않습니다. 꼭 기억하세요. 자식 필터를 사용하는 경우에는 인덱스가 1부터 시작한다는 것을요.

이로써, 기본 셀렉터에서 사용할 수 있는 필터들을 어느 정도 정리한 것 같네요. 물론, 아직 visible 관련 필터(2개)가 남아있긴 한데요. 이 부분은 다음 강좌의 시작부에서 가볍게 정리하기로 하겠습니다.

다음 강좌의 본격적인 내용은 사실 셀렉터의 하이라이트라고 할 수 있는 폼 셀렉터에 대한 이야기입니다. 입력 UI를 구현하려면 피해갈 수 없는 폼 요소들을 셀렉터를 이용해서 쉽게 선택할 수 있는 것이 바로 폼 셀렉터인데요. 그러한 셀렉터들을 살펴봄으로써 jQuery의 기본인 셀렉터에 대한 이야기를 완전하게 마무리하도록 하겠습니다.

사실, 이러한 분류는 실제 jQuery 온라인 문서에 나온 분류를 기반으로 말씀을 드리고 있습니다. 해서, 제가 설명드린 셀렉터들에 대해서 개별적으로 조금 더 자세한 설명을 보고 싶다 하시면, http://docs.jquery.com/Selectors 페이지에 가셔서 각각의 셀렉터를 클릭하여 자세한 설명과 함께 라이브 데모 및 소스까지 즐기실 수 있습니다. 꽤 많은 셀렉터가 있지만, 태오와 함께 깔끔한 강좌로 같이 정리해 나가니 생각보다 많게 느껴지시지 않죠? 어쩌면 jQuery의 공식문서보다 저의 강좌가 더 명쾌하게 느껴지실 지도 모르겠습니다(네. 왠지 태오 갑자기 재수가 좀 없군요…).

그러면, 다음 강좌에서 또 뵙겠습니다. 잘 읽으신 분은 /환호 /토닥 한번씩 날려주세요.


authored by Taeyo

Posted by 바람이불면
,