본문 바로가기
개발/jQuery

플러그인 만들기

by GetLight 2010. 8. 6.


Query 홈페이지에 있던 플러그인 제작 방법에 관한 문서입니다. 플러그인을 제대로 된 형태에 맞춰 작성하게 되면 범용성, 재사용성도 높아지고 코드도 보기 좋아지죠^^ 읽기 귀찮으실 분들이 혹 있을지도 몰라서 번역해봤습니다. 아무래도 영어실력도 국어실력도 짧은 터라 오히려 더 읽기 어려울지도 모르겠지만...
원본 글은 여기를 클릭해서 볼 수 있습니다. - LazyGyu

플러그인/저작

jQuery는 메소드와 함수를 플러그인으로 넣을 수 있는 방법을 제공합니다. 기본적으로 다운로드 되는 대부분의 메소드와 함수들은 jQuery 플러그인 구조를 이용해 만들어져 있습니다.

플러그인은 두 단계를 거쳐 만듭니다. 첫번째는 공용(public) 함수와 메소드를 작성하는 것입니다. 예를 들면 아래와 같습니다.

jQuery.fn.debug = function() {
return this.each(function(){
alert(this);
});
};
jQuery.log = function(message) {
if(window.console) {
console.debug(message);
} else {
alert(message);
}
};

코더들은 다음과 같이 당신의 새 플러그인을 호출할 수 있습니다.

$("div p").debug();

혹은 함수를 사용할 수 있습니다.

try {
// do some error prone stuff
} catch(exception) {
$.log(exception);
}

몇가지 기억해 두어야 할 중요한 사안이 있습니다.

  • 파일명을 jquery.[플러그인명].js 로 짓도록 합니다. 예 : jquery.debug.js
  • 모든 새로운 메소드는 jQuery.fn 개체에 종속되도록 하고, 모든 함수는 jQuery 개체에 종속되게 합니다.
  • 메소드 내에서 'this' 인스턴스는 현재 jQuery 개체를 가리킵니다.
  • 새로 덧붙인 모든 메소드와 함수는 반드시 세미콜론(;)으로 끝나야 합니다 - 그렇지 않으면 파일을 압축할 때 코드가 깨지기 때문입니다.
  • 메소드는 특별히 명시된 상황이 아닌 한 반드시 jQuery 개체를 반환해야 합니다. 
  • this.each 를 사용해서 현재 엘리먼트 셋에 접근해야 합니다 - 이렇게 하면 코드는 깔끔하고 호환성이 높아집니다.
  • 항상 메소드를 $ 대신에 jQuery 에 바로 추가하도록 합니다. 그래야 사용자는 noConflict() 를 통해 자신만의 이름을 사용할 수 있습니다. 사용자 별명 섹션 아래를 읽도록 합니다. 고상한 해결책은 $를 내부에서 사용하되, 메소드는 첫째 jQuery 개체에 추가하는 것입니다.

만일 플러그인의 전체적인 모습이 어떻게 이루어졌는지 궁금하다면, 플러그인 탐색 이나 jQuery 소스 코드를 볼 수 있습니다.

위쪽의 내용은 작고 단순한 플러그인에는 충분하지만 다른 경우, 좀 더 지능적인 방법이 필요합니다.

목차


개체 내의 정적인 함수 모으기

만약 여러개의 정적인 메소드가 필요하다면, 하나의 개체에 그것들을 추가해야 합니다. 예를 들어 다음과 같이 시작했다면,

jQuery.logError = function() { ... };
jQuery.logWarning = function() { ... };
jQuery.logDebug = function() { ... };

아래와 같이 바꿉니다.

jQuery.log = {
error : function() { ... },
warning : function() { ... },
debug : function() { ... }
};

이렇게 해서 네임스페이스가 어지럽혀지지 않고, 많은 문제를 회피할 수 있습니다.


변수 숨기기

반복문 내에서 플러그인 메소드를 정의하는 데는 일일이 열거하는 것 말고도 다른 방법이 있습니다.

예를 들면:

var newMethods = {
check  : function() { ... },
uncheck  : function() { ... },
toggleCheck : function() { ... }
};
jQuery.each(newMethods, function(i) {
jQuery.fn[i] = this;
});

만약 newMethods 변수를 다른 코드로부터 숨기고 싶다면, 저 코드를 즉시 실행되는 함수로 감쌉니다. (변수의 종결부분을 만듭니다)

(function() {
var newMethods = {
check  : function() { ... },
uncheck  : function() { ... },
toggleCheck : function() { ... }
};
jQuery.each(newMethods, function(i) {
jQuery.fn[i] = this;
});
})();

설정

수 많은 매개변수를 일일이 열거하지 않아도 사용할 수 있도록 플러그인을 디자인하는 연습을 하는 것이 좋습니다. 가능한한 유연하게 만들기 위해서는, 재치있는 기본값을 가진 몇몇 설정을 제공해야 합니다. 매개변수로 URL이 항상 필요하고, 'name'(문자열), 'size'(숫자), 'global'(논리) 의 선택사항을 가진 플러그인을 고찰해봅시다.

플러그인은 아래와 비슷하게 만들어질겁니다.

jQuery.fn.pluginName = function(url, options) {
// define defaults and override with options, if available
// by extending the default settings, we don't modify the argument
settings = jQuery.extend({
name: "defaultName",
size: 5,
global: true
}, options);

// do the rest of the plugin, using url and settings
}

이 플러그인은 아래처럼 선택사항 없이 사용할 수 있습니다.

$('selection').pluginName('mypage.php');

혹은 두세개의 선택사항과 함께 사용할 수도 있습니다.

// override defaults for name and size, but not global
var options = {
name: "foobar",
size: 10
}
$('selection').pluginName('mypage.php', options);


관련 읽기: Mike Alsup 은 굉장한 플러그인 개발 패턴을 작성했습니다. 모든 주석을 읽어보세요. 샘플 코드에는 약간의 버그가 있습니다.


jQuery.extend 를 사용하여 jQuery를 확장하기

위 쪽 섹션에서, 우리는 플러그인 설정 개체를 확장하기 위해 jQuery.extend(setting, options)를 사용했습니다. 이제, 두개나 그 이상의 개체 대신에 단 하나의 개체만을 이용해서, 우리는 jQuery.extend 함수를 매개 변수를 포함해 jQuery 개체 자체를 확장하는 데 사용할 수 있습니다. 이것은 jQuery의 다른 모든 외관에 가깝게 무언가를 추가할 수 있도록 허락합니다. 새 메소드를 예로 들면:

jQuery.fn.extend({
check  : function() { ... },
uncheck  : function() { ... },
toggleCheck : function() { ... }
});

하지만 jQuery.extend 를 jQuery 내에서 정의된 다른 개체를 확장하는 데 사용할 수도 있습니다. (예를 들면 새로운 셀렉터를 추가하는 것과 같은)

jQuery.extend(jQuery.expr[":"], {
text  : "a.type=='text'",
radio  : "a.type=='radio'",
checkbox : "a.type=='checkbox'"
});

애니메이션 제작하기

플 러그인이 확정된 이벤트를 위해 애니메이션을 사용해야 할 수도 있습니다. 예를 들어 탭 플러그인은 탭을 변경할 때 페이드(fade)나 슬라이드(slide) 애니메이션을 사용합니다. 애니메이션을 필요에 따라 재작성하는 것은 animate 메소드를 사용하면 간단합니다. (자세한 내용은 API 문서를 참조하세요) 아래의 예제는 기본적으로 페이드를 사용합니다.

jQuery.fn.foobar = function(settings) {
settings = jQuery.extend({
animation: {opacity: "hide"}
}, settings);
// use the animation setting as a parameter for animate
jQuery(...).animate(settings.animation);
}

애니메이션을 위한 설정을 넘겨줌으로써 슬라이드를 사용할 수 있습니다.

jQuery(...).foobar({
animation: {height: "hide"}
});

개인별 명칭

플 러그인 코드 내에서 "$"를 사용하지 않는 것인 좋은 상태입니다. 이 것은 jQuery 와 플러그인 사용자에게 "$"를, 예를 들면 "jQ" 같은 것으로 바꿀 수 있게 해줍니다. 이것은 "$"를 사용하는 다른 라이브러리나 프레임워크를 사용하기 위해선 꼭 필요합니다.

물론, $ 는 아주 편리한 단축명칭이고, 이 것을 사용하지 않는 대신에 우리는 이 것의 존재도 신뢰해선 안됩니다. 대신, 우리는 간단하게 자신만의 별칭 (이 것을 "$"라고 부릅시다)을 코드에 사용할 수 있습니다.

플러그인 코드 내에서의 명칭

아래의 방법은 모든 플러그인 코드 내에 함수를 하나 만들고 즉각 실행시킵니다. 구조는 아래와 같이 생겼습니다.

(function() {
// put plugin code here
var xyz; // xyz is NOT a global variable, it is only visible inside this function
})(); // execute the function immediately!

부가적인 괄호는 반드시 필요합니다! 괄호 없이는 무기명 함수를 실행시킬 수가 없습니다.

자, 이제 재밌는 부분입니다.

(function($) {
// plugin code here, use $ as much as you like
})(jQuery);

우리는 "jQuery"를 함수에 넘겨주어 어떤 명칭이든 우리가 좋아하는 것으로 사용할 수 있게 되었습니다. 그러므로 "$" 대신 JavaScript 변수명으로 가능한 다른 어떤 값이든 사용할 수 있습니다.

이것을 사용하는 플러그인을 보려면 툴팁 플러그인을 참조하세요.


페이지 코드 내에서의 명칭

플 러그인 사용법을 그리는 예제를 만들기 위해 jQuery 코드를 작성할 때, 향후 호환이 가능하게 만들어주는 기술에 대해 고심할지도 모릅니다. 많은 jQuery 예제 코드들(많은 플러그인을 포함한 광범위한 예제들)은 $ 를 사용하여 작성되었습니다. 이것은 당신의 플러그인을 사용하려는 다른 사람들이 $를 다른 용도로 이미 사용하고 있을 때 문제가 될 수 있습니다.

이것을 방지하기 위해, 예제 코드를 DOM ready 이벤트 핸들러에 써 넣을 수 있습니다.  첫번째 인자는 함수 내에서 $ 가 될 수도 있고, 다른 어떤 것도 사용할 수 있으며, 이 것은 해당 함수 내에서 jQuery 의 별칭으로 사용됩니다.

 jQuery(function($) {
// your code using $ alias here
});

이 방법으로, jQuery 를 한 번만 타이핑하고도 ready 핸들로 코드 내에서 별칭을 안전하게 사용할 수 있습니다. 더 많은 정보를 원하면, 이 기술에 대한 경고를 포함한 jQuery 와 다른 라이브러리를 함께 사용하기를 보도록 합니다.


함께 넣기

아래에 당신의 플러그인을 개발하기 시작하는 데 사용할 수 있는 짧은 샘플 코드가 있습니다.

 (function($) {

$.fn.myPlugin = function(settings) {
var config = {'foo': 'bar'};

if (settings) $.extend(config, settings);

this.each(function() {
// element-specific code here
});

return this;

};

})(jQuery);


이 예제 내에서 "config" 변수는 플러그인을 위한 기본적인 설정을 담은 개체로 사용됩니다. (예를 들면, "{'speed':1000}"과 같은.) 이것은 함수가 호출될 때 선택적으로 넘겨진 "settings" 개체를 확장해 사용합니다.

중간의 each() 메소드는 미리 jQuery 셀렉터를 통해 선택해 플러그인으로 넘겨진 개체들에 대한 반복입니다. 예를 들어, 만약 플러그인이 아래와 같이 호출되었다면,

 $('p').myPlugin();

each() 메소드는 페이지 내의 모든 문단 태그를 반복하게 됩니다.

이 예제에서 가장 중요한 부분은 "return this;" 입니다. 이것은 플러그인이 호출 될 때 남아있을지도 모르는 jQuery 체이닝을 보장하기 위해 필요합니다. 다시 말해 사람들이 당신의 플러그인을 호출한 뒤에 다른 메소드를 덧붙일지도 모른다는 뜻입니다.

 $.myPlugin({'foo': 'bar'}).fadeOu