jQuery의 유틸리티 함수

jQuery의 플러그인 기능 중에 유틸리티 성격의 플러그인을 정리해 봅니다. 정리해 놓으면 딱 필요할때 익숙하게 사용할 수 있겠지요.

먼저 문자열 앞뒤의 공백 문자를 제거해 주는 코드입니다.

var s = '   You are, you will be good.      ';
s = $.trim(s);

다음은 배열의 값이나 객체의 키-값들을 순회하는 each 함수이며, 예제 코드는 아래와 같습니다.

$.each(['foo', 'bar', 'baz'], function (i, v) {
    alert(i + " : " + v);
});

$.each({ foo: 'bar', baz: 'bim' }, function (k, v) {
    alert(k + ' : ' + v);
});

그리고 어떤 값이 배열에 속해 있는지를 검사하는 플러그인입니다.

var myArray = [1, 2, 3, 4, 5];
if ($.inArray(4, myArray) !== -1) {
    alert('found.');
}

다음은 어떤 객체에 또 다른 객체의 키-값을 복사해 주는 플러그인입니다. $.extend의 첫번째 인자는 복사가 되어 값이 저장될 대상 객체입니다. 그리고 두번째 이후의 인자는 복사될 키-값을 담고 있는 객체들입니다. 아래의 코드는 secondObj의 키-값을 firstObj에 복사해 주는 코드인데요. 결국 firstObj.foo는 secondObj.foo의 값으로 변경됩니다. $.extend는 첫번째 인자를 반환하므로 newObject === firstObj는 true입니다.

var firstObj = { foo: 'bar', a: 'b' };
var secondObj = { foo: 'baz' };
var newObject = $.extend(firstObj, secondObj);

alert(firstObj.foo);

if (newObject === firstObj) {
    alert('equal');
}

다음 코드는 함수 호출시 내부의 this를 개발자가 의도한 객체로 하여 함수를 호출하도록 하는 플러그인입니다. 아래의 코드에서 myFunction는 전역 객체인 Window의 소유로 이 함수를 그대로 호출하면 함수 내부에서 this는 Window 객체가 됩니다. 그러나 12번 코드를 통해 myFunction 함수에 대한 내부 this를 myObject로 변경해주는 함수로 myProxyFunction를 생성하고 있습니다. 실제로 이 myProxyFunction를 13번 코드처럼 그대로 호출하면 함수 내부의 this는 myObject가 됩니다. JavaScript의 이벤트 리스너 함수에서 this 객체가 다소 혼란스러울 때가 있습니다. 이 혼란의 시기에 이 플러그인이 해결점이 될 수 있겠습니다.

var myFunction = function () {
    alert(this);
};

var myObject = {
    foo: 'bar',
    toString: function () { return 'myObject'; }
};

myFunction();

var myProxyFunction = $.proxy(myFunction, myObject);
myProxyFunction();

다음은 배열을 순회하면서 원하는 값들로 구성된 배열을 생성하는 플러그인입니다. 7번 코드의 실행을 통해 arr 배열의 요소 객체의 id 속성만으로 구성된 배열을 생성해 반환합니다. 11번 코드는 새롭게 생성된 배열의 값을 확인하는 코드입니다.

var arr = [
    { id: 'a', tagName: 'li' },
    { id: 'b', tagName: 'li' },
    { id: 'c', tagName: 'li' }
];

var result = $.map(arr, function (value, index) {
    return value.id;
});

$.each(result, function (i, v) {
    alert(i + ' : ' + v);
});

다음은 특정 객체의 타입이 무엇인지를 확인하는 플러그인입니다.

alert($.isArray([])); // true
alert($.isFunction(function () { })); // true
alert($.isNumeric(3.14)); // true

alert($.type(true)); // boolean
alert($.type(3)); // number
alert($.type('test')); // string
alert($.type(function () { })); // function
alert($.type([])); // array
alert($.type(null)); // null
alert($.type(/test/)); // regexp
alert($.type(new Date())); date

크로스 도메인(Cross Domain)을 허용하는 OpenAPI 개발을 위한 JSONP

AJAX 방식은 서로 다른 도메인간의 데이터를 받아 오는 것을 기본적으로 막고 있지만, JSONP라는 방법을 이용해 가능하게 됩니다. 이에 대해 정리해 봅니다. JSONP 방식의 OpenAPI를 제공하는 Java 서블릿 중 doGet 함수는 다음과 같습니다.

protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    throws IOException
{
    String name = request.getParameter("name");
    String nameDecoded = URLDecoder.decode(name, "UTF-8");
    String callbackFunction = request.getParameter("callback");

    String responseData = "({\"Value\": \"Hello, " + nameDecoded + "\"})";
		
    String result = callbackFunction + "("+ responseData + ");";

    response.setContentType("application/json;charset=UTF-8");
    response.setCharacterEncoding("UTF-8");
    response.setStatus(HttpServletResponse.SC_OK);
		
    response.setContentType("text/javascript");
    PrintWriter out = response.getWriter();
    out.println(result);
}

위의 OpenAPI는 클라이언트 측에서 name과 callback이라는 파라메터를 전달해 준다라는 전제 조건을 갖습니다. 서버는 자신에게 전달된 name을 이용해 클라이언트에게 다시 Hello로 구성된 문자열을 결과로 전달해 줍니다. 여기서 전달 방식이 중요한데요. 그 전달방식이 바로 JavaScript 함수호출에 대한 코드입니다. 이 코드 문자열을 클라이언트가 받아 실행해 준다라는 것입니다. 실제로 위의 서블릿에 대해 웹 브러우저를 통해 호출해 보면 다음과 같습니다.

위의 URL 호출을 좀더 설명하면, name 파라메터에는 Dip2K를 지정했고, callback 파라메터에는 Test를 지정했습니다. 그 호출 결과는 Value를 키로 하고 Hello, Dip2K를 값으로 하는 객체를 인자로한 Test 함수의 호출 코드에 대한 문자열입니다. 클라이언트에서 이 문자열을 코드화하여 실행해주면 성공적으로 서버에서 전달한 데이터를 받아 처리할 수 있게 되는 것입니다.

실제로 아래의 코드는 jQuery를 이용해 JSONP 방식으로 크로스도메인 문제를 깔끔하게 해결해 데이터를 주고 받는 코드입니다.

var url = 'http://www.gisdeveloper.co.kr:8079/OpenAPI?name=김형준&callback=?';

$.ajax({
    url: url,
    type: 'get',
    dataType: 'jsonp',
    success: function (data) {
        alert(data.Value);
    }
});

실행 결과는 ‘Hello, 김형준’을 표시하는 Alert 창 입니다.

웹 애니메이션 3/3 ㅡ requestAnimationFrame 활용 방식

웹에서 애니메이션을 구현하는 세번째 방식은 javascript 코드를 사용해 애니메이션될 객체의 속성의 변경하는 것으로써 requestAnimationFrame API를 이용해 속도를 향상시키는 방식입니다. requestAnimationFrame API가 제공되기 이전에는 타이머를 사용하였으나, 이 타이머는 불확실하고 느리다는 단점이 있어 현재는 사용하지 않습니다. (아.. 한게임 하고 왔더니 머리가 띵… 하네.. @_@;) 아래는 이 requestAnimationFrame 함수를 이용한 애니메이션에 대한 예입니다.

[xyz-ihs snippet=”requestAnimation”]

SVG를 사용했고 path를 이용해 도형을 구성하였습니다. 도형의 선형 대쉬 스타일인 strokeDashOffset 속성을 주기적으로 변경함으로써 매치 행군하는 벌레 애니메이션을 구현할 수 있습니다. 이 예에 대한 코드를 살펴 보겠습니다.

먼저 svg와 도형에 대한 path 정의입니다.


    

path에 chain_st라는 클래스가 지정되어 있습니다. chain_st 클래스는 다음과 같습니다.

.chain_st {
    stroke-width: 1;
    stroke: #f00;
fill: transparent;
}     

svg {
    width:100%;
} 

단순히 path의 선굵기과 색상, 그리고 채움색은 투명으로 지정하고 있습니다. 덧붙여 svg의 폭을 현제 부모 너비를 꽉 채우도록 7~9번 코드에서 지정하고 있습니다.

이제 애니메이션 코드인데, 아래와 같습니다.

var p = document.querySelector('.chain_st'),
offset = 5;

var offsetMe = function () {
    if (offset < 0) offset = 5;
    p.style.strokeDashoffset = offset;
    offset--;

    requestAnimationFrame(offsetMe);
}

offsetMe();

offsetMe 함수를 호출할때마다 strokeDashOffset의 값을 변경하고 있는 6번 코드를 주목하기 바랍니다. 이 offsetMe 함수는 requestAnimationFrame API를 통해 주기적으로 호출됩니다.

웹 애니메이션 2/3 ㅡ keyframe animation 방식

웹에서 애니메이션을 제공하는 방식 중 두번째는 Keyframe 개념으로 접근하는 것입니다. 이는 전체 애니메이션을 100%라고 할때 각 단계마다 애니메이션될 속성값을 지정해 주는 방식으로써 그 중간 화면은 자동으로 계산해 줍니다. 아래의 화면은 Key frame Animation 방식을 사용한 애니메이션에 대한 화면입니다.

[xyz-ihs snippet=”keyframe-Animation”]

위의 화면에 대한 예를 통해 키프레임 애니메이션을 정리해 보겠습니다.

가장 먼저 움직이는 노란 사각형에 대한 div에 대한 코드입니다.

이 div의 클래스는 box인데, 아직 크기와 색상과 같은 스타일이 지정되지 않은 상태이므로 이 box 클래스에 해당 스타일을 아래처럼 지정합니다.

    .box {
        width: 100px;
        height: 100px;
        background: #ffd800;
        box-shadow: 0 10px 20px rgba(0,0,0,0.5);

        animation-name: movingBox;
        animation-duration: 2300ms;
        animation-iteration-count: infinite;
        animation-direction: alternate;
    }

2~5번가지의 코드가 div의 크기와 색상 그리고 그림자에 대한 스타일 지정입니다. 7~10번 코드는 키프레임 애니메이션에 대한 스타일입니다. 7번 코드는 구체적인 키프레임에 대한 아이디값이고, 8번은 애니메이션이 진행되는 시간을 2.3초로 지정했으며, 9번은 무한반복, 10번은 무한반복시 반복방향을 지정하는 코드입니다. 이제 7번에서 지정한 키프레임에 대한 아이디인 movingBox에 대한 정의는 다음과 같습니다.

@keyframes movingBox {
    0% {
        transform: translate(0, 0);
        opacity: 0.3;
    }

    25% {
        opacity: 0.9;
    }

    50% {
        transform: translate(400px, 0);
        opacity: 0.2;
    }

    100% {
        transform: translate(100px, 0);
        opacity: 0.8;
    }
}

코드를 살펴보면, 초기단계(0%)와 1/4지점(25%) 그리고 중간지점(50%) 및 끝지점(100%)의 상태에서의 위치와 투명도를 지정함으로써, 각 단계의 중간결과를 자동으로 계산하여 애니메이션이 이루어지도록 하고 있습니다.

웹 애니메이션 1/3 ㅡ Transition 방식

이글은 웹에서 화면에 표시된 객체에 대한 애니메이션을 적용하는 방식 중 Transition 방식에 대한 정리입니다. 현대의 UI에 애니메이션을 적용한다는 것은 사용자에게 영감을 불어 넣을 수 있다는 점에 매우 철학적이고 세련된 방법이라고 할 수 있습니다.

먼저 아래의 화면에서 ‘터치미!’ 텍스트(div 요소)를 클릭해 보시기 바랍니다.

[xyz-ihs snippet=”Transition”]

클릭할 때마다 좌에서 우로.. 우에서 좌로 이동하는 것을 살펴볼 수 있습니다. 위의 예제에 대한 코스를 살펴 보겠습니다. 먼저 화면에 표시되는 ‘터치미!’에 대한 div 요소입니다.

터치미!

div에 box라는 클래스를 지정하고 있습니다. box 클래스에 대한 정의는 다음과 같습니다.

    .box {
        font-family: '맑은 고딕';
        text-align: center;
        line-height: 100px;

        width: 100px;
        height: 100px;

        background: #FFF;
        box-shadow: 0 10px 20px rgba(0,0,0,0.5);

        transform: translate(0, 0);
        transition: transform 1000ms;
    }

2번~4번 코드는 div의 ‘터치미!’ 텍스트에 대한 폰트와 정렬을 지정하고 있고, 6번~7번은 div의 너비와 높이에 대한 크기를 지정하고 있습니다. 그리고 9~10번 코드는 div의 색상과 그림자를 표시하도록 하고 있습니다. 12번은 최초의 div의 위치를 (0, 0) 좌표로 지정하고 있습니다. 13번 코드가 바로 애니메이션을 위한 transition(전환)을 지정하고 있는데, transform에 대해 1초(1ms) 동안 애니메이션이 이루어지도록 하고 있습니다. 그러나 여기서는 아직 transform에 대해 어떤 전환이 이루어질지에 대한 코드는 없습니다. 이떤 전환이 이루어지는 시점은 이 div를 클릭할 때인데, 다음의 코드가 필요합니다.

var box = document.querySelector('.box');

box.addEventListener('click', function () {
    box.classList.toggle('move');
});

box.addEventListener('transitionend', function () {
    alert('이동 완료');
}, false);

3번 코드에서 div에 대한 클릭 이벤트를 지정하고 있습니다. 즉, div에 move라는 클래스를 토글링하고 있는데요. 토글링은 해당 값이 지정되어 있으면 제거하고, 지정되어 있지 않으면 지정하는 방식입니다. move 클래스는 다음과 같습니다. (참고로 7번 코드는 하나의 애니메이션이 완료되었을 때 호출되는 함수를 지정하고 있음)

    .box.move {
        transform: translate(400px, 0);
    }

보시면 transform 속성에 대해서 x축으로 400px로 변경하고 있습니다.