Web Tech/jQuery

jQuery.expr[':'] 확장 및 활용 방법 - jQuery 가상 선택자 사용자 정의

jaiyah 2016. 1. 19. 10:49

jQuery.expr.pseudos 확장(사용자 정의 방법)과 활용

:hidden, :visible 과 같은 제이쿼리의 가상 선택자를 사용자가 직접 정의, 확장하는 방법에 대해 알아봅니다.




jQuery.expr.pseudos 확장

사용자 정의 가상 선택자를 확장하는 Sizzle 엔진의 새로운 방법은 jQuery.expr.createPseudo() 메소드를 사용하는 것입니다.

이 메소드는 사용자가 직접 정의한 가상 클래스 선택자에 메타 값을 입력하는 경우에만 사용할 수 있습니다.


아래 코드를 간단히 살펴봅니다.

javascript
// jQuery.expr[':'] === jQuery.expr.pseudos

$.expr[':'].btn = $.expr.createPseudo( function(meta){
    return function(el) {
        console.log(
                '--- element ---\n', el,
                '\n\n--- meta 값 ---\n', meta
        );
    }
} );

위 코드에서는 :btn 이라는 가상 선택자를 사용자가 정의한 것입니다.

그리고 <a> 요소가 하나 있는 상태에서 아래와 같이 jQuery의 가상 선택자를 선택하는 것과 동일하게 입력하면..

javascript
$('a:btn(play)');

콘솔창(크롬에서 테스트)에는 다음과 같이 출력이 될 것입니다.

javascript
--- element ---
<a href></a>  또는 a

--- meta 값 ---
play




expr[':'] 을 어디에 사용하면 유용할까?

그렇다면 위와 같은 방법을 어디에서 사용하면 유용한 것일까요?

예를 들어 요소의 클래스 속성값이 'btn'이고, 포함하는 문자열이 'play'인 요소를 찾고자 한다고 가정합시다.

html
<a class="btn">play</a>


위 요소에 해당되는 대상을 매우 손쉽게 찾고자 가상 선택자를 만들고자 한다면 아래와 같이 코드를 작성할 수 있습니다.

javascript
$.expr[':'].btn = $.ex.createPseudo( function(meta){
    return function(el) {
        return meta ?
            el.className.match(/btn/ig) && (el.textContent || el.innerText) === meta :
            el.className.match(/btn/ig);
    }
} );

위와 같이 작성한 후, 사용자가 정의한 가상클래스 선택자 코드를 작성하여 실행하면 원하는 대상을 찾을 수 있습니다.

즉, 사용자가 원하는 형태로 가상 클래스 선택자를 확장할 수 있다는 것입니다.

javascript
$('a:btn(play)').css( 'border', '2px solid red' );



See the Pen $.expr 기초 by jaeheekim (@jaehee) on CodePen.




$.expr[':'] 활용 코드 살펴보기

다음의 코드는 엘리먼트가 inline 요소(사용자가 block 요소를 inline 요소로 변경했을 경우도 포함) 및 block 요소인 것을 찾아내어 선택할 수 있는 코드입니다.

javascript
/**
 * --------------------------------------------
 * display: inline 요소를 찾는 sudo Expression
 * --------------------------------------------
 */
 if (!$.expr[':'].inline) {
     $.expr[':'].inline = function(el, index, meta) { // 메타 인자는 :inline() 괄호 안의 인자값을 나타낸다.
        return $(el).css('display') === 'inline';
    }
 }

 if (!$.expr[':'].block) {
     $.expr[':'].block = function(el, index, meta) {
        return $(el).css('display') === 'block';
    }
 }


다음 아래와 같이 <a> 요소에 클래스와 data- 프로퍼티값이 설정되어 있을 경우에 가상 선택자를 확장하는 예입니다.

html
<a href="#none" class="btn-01" data-btn="new-anchor">앵커 버튼</a>
javascript
$.extend(jQuery.expr[':'], {
    button: function(el, index, meta) {
        return el.nodeName.toLowerCase() === "a" && el.className.match("btn") && el.dataset.btn === meta[3];
    }
});

$("a:button(new-anchor)").css('border', '2px solid red');




$.expr advanced usage

display 속성값으로 가상 선택자를 확장해 보도록 합니다.

javascript
/**
 * -----------------------------------------
 * display sudo Expression 확장 (반복문 처리)
 * -----------------------------------------
 */

var display_value = 'inline, block, inline-block, none, list-item'.split(', '),
    i = 0,
    len = display_value.length,
    d_value;


for (; i < len; i++) {

    d_value = display_value[i];
    // 반복문에서 아래와 같은 코드 작성시에 i 는 전역변수가 되기 때문에 주의가 필요
    // 그렇기 때문에 클로저를 이용한다.

    // console.log(d_value);

    if (!$.expr[':'][d_value]) {
        // 클로저를 이용 (반복문을 사용할 시 주의해야 함)
        // 첫번째 외부함수가 즉시 실행되면서 인자값으로 d_value 를 넘겨주고
        // 첫번째 리턴, 즉 콜백함수가 리턴되면서 $.expr[':'][d_value] 에 담기게 된다.
        // 또한 외부함수의 @param d_value 는 지역변수와 같기 때문에 콜백(내부)함수에서 d_value 값을 계속 참조하고 있을 수 있다.
        // 다시 말해서, 내부함수의 지역변수가 외부함수의 지역변수를 계속 참조하도록 하는 것이다.
        $.expr[':'][d_value] = (function(d_value) { //  d_value 는
            return function(el) {
                return $(el).css('display') === d_value;
            }
        })(d_value); // 반복문 i 인 display_value[i]를 외부함수에 넘겨준다.
    }

}

$('li:inline-block').css('border', '1px solid red');


위의 코드를 아래와 같이 리팩토링해 봅니다.

javascript
'use strict';
/**
 * display sudo Expression 확장 (반복문 처리)
 * jQuery.expr[':'] 확장 - display
 * http://www.w3schools.com/cssref/pr_class_display.asp
 * --------------------------------
 */
var filter = 'inline, inline-block, block, list-item, table, inline-table, table-caption, table-row, table-cell, table-column, flex, inline-flex'.split(', '),
    k      = 0,
    l      = filter.length;

for(; k < l; k++) {
    (function(display_value){
        $.expr[':'][display_value] = function(el) {
            return $(el).css('display') === display_value;
        }
    })(filter[k]);
}


See the Pen $.expr display 속성값으로 가상 선택자 정의 by jaeheekim (@jaehee) on CodePen.



Jaehee's WebClub