제이쿼리 사용자 정의 이벤트 질문입니다.
본문
tabPanel1.setSelectPanel(e.selectIndex);
})
$(document).ready(function() {
// 탭메뉴 코드가 동작할 수 있도록 tabMenu() 함수 호출
var tabMenu = $("#tabMenu1");
$tabMenu.on("tabSelect", function(e) {
tabPanel1.setSelectPanel(e.selectIndex);
})
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title> </title>
<style>
.tab-menu {
list-style: none;
height:80px;
}
.tab-menu li {
width:99px;
height:40px;
background-position-y:0;
text-indent: -1000px;
overflow: hidden;
display: inline-block;
float:left;
}
.tab-menu li:hover {
background-position-y: -40px;
}
.tab-menu li.select {
background-position-y: -80px;
height:80px;
}
.tab-menu li.menuitem1 {
background-image: url(./images/newbtn.bar.1.png);
}
.tab-menu li.menuitem2 {
background-image: url(./images/newbtn.bar.2.png);
}
.tab-menu li.menuitem3 {
background-image: url(./images/newbtn.bar.3.png);
}
.tab-menu li.menuitem4 {
background-image: url(./images/newbtn.bar.4.png);
}
.tab-menu li.menuitem5 {
background-image: url(./images/newbtn.bar.6.png);
}
.tab-contents {
position:relative;
left:10px;
top:10px;
width:780px;
height:340px;
overflow:hidden;
background:url(./images/content_bg.png) no-repeat;
}
.tab-contents .content{
position: absolute;
left:10px;
top:10px;
display:none;
}
.tab-contents .content.select{
display:block;
}
</style>
<script src="../../../libs/jquery-1.11.0.min.js"></script>
<script>
var tabPanel1 = null;
$(document).ready(function() {
// 탭메뉴 코드가 동작할 수 있도록 tabMenu() 함수 호출
var tabMenu1 = tabMenu("#tabMenu1");
tabMenu1.$tabMenu.on("tabSelect", function(e) {
tabPanel1.setSelectPanel(e.selectIndex);
})
// 탭패널 기능 호출
tabPanel1 = tabPanel(".tab-contents");
});
// 탭메뉴 기능 구현하기
function tabMenu(selector) {
var $tabMenu = null;
var $menuItems = null;
// 선택 한 탭메뉴를 저장할 변수
var $selectMenuItem = null;
// 요소 초기화, tabMenu() 함수 내부에서 사용할 공통 데이터는 모두 이곳에 작성해주세요.
function init() {
$tabMenu = $(selector);
$menuItems = $tabMenu.find("li");
}
// 이벤트 등록은 모두 이곳에 작성해주세요.
function initEvent() {
$menuItems.click(function() {
setSelectItem($(this));
});
}
// 선택 메뉴 아이템 만들기
function setSelectItem($item) {
if ($selectMenuItem) {
$selectMenuItem.removeClass("select");
}
$selectMenuItem = $item;
$selectMenuItem.addClass("select");
// 이벤트 발생
dispatchSelectEvent();
}
// index번째 메뉴 아이템 선택
function setSelectItemAt(index) {
var $item = $menuItems.eq(index);
setSelectItem($item);
}
// 이벤트 발생
function dispatchSelectEvent() {
// 이벤트 객체 생성
var event = jQuery.Event("tabSelect");
// 이벤트에 담아 보낼 데이터 연결
event.selectIndex = $selectMenuItem.index();
event.$selectItem = $selectMenuItem;
$tabMenu.trigger(event);
}
init();
initEvent();
return {
$tabMenu : $tabMenu,
setSelectItemAt : setSelectItemAt
}
}
// 탭패널 기능 구현하기
function tabPanel(selector) {
var $tabPanels = null;
var $selectPanel = null;
function init(selector) {
$tabPanels = $(selector).find(".content");
}
function setSelectPanel(index) {
if ($selectPanel) {
$selectPanel.removeClass("select");
}
$selectPanel = $tabPanels.eq(index);
$selectPanel.addClass("select");
}
init(selector);
// 선택기능 리턴
return {
setSelectPanel : setSelectPanel
}
}
</script>
</head>
<body>
<ul class="tab-menu" id="tabMenu1">
<li class="menuitem1">google</li>
<li class="menuitem2">facebook</li>
<li class="menuitem3">pinterest</li>
<li class="menuitem4">twitter</li>
<li class="menuitem5">path</li>
</ul>
<div class="tab-contents">
<div class="content">
<img src="images/content_facebook.png">
</div>
<div class="content">
<img src="images/content_google.png">
</div>
<div class="content">
<img src="images/content_pinterest.png">
</div>
<div class="content">
<img src="images/content_twitter.png">
</div>
<div class="content">
<img src="images/content_path.png">
</div>
</div>
</body>
</html>
답변 6
일단, 코드는 동작을 합니다.
// 1.
// tabMenu 함수에서 tab 클릭하면
// 메뉴에 select class 를 추가하고
// select 된 index 와 element 를 담은 이벤트를 trigger 합니다.
// 이때 이 tabMenu 함수는 selector 를 인자로 받죠. html 에서 뭐가 메뉴인지 알아야 하니까..
function tabMenu(selector) {
....
}
2. tabMenu 와 tabPanel 을 연결시켜주는 코드는..
$(document).ready(function () {
// 탭메뉴 코드가 동작할 수 있도록 tabMenu() 함수 호출
var tabMenu1 = tabMenu("#tabMenu1");
// 탭패널 기능 호출
var tabPanel1 = tabPanel(".tab-contents");
tabMenu1.$tabMenu.on("tabSelect", function (e) {
tabPanel1.setSelectPanel(e.selectIndex);
});
});
맞게 하신것 같네요...
!-->!-->2. 그 부분은 제 실수네요 ^^;;;
...
// jQuery chainning 을 위해 반환
return this.each(function() {
// $(this) 는 $(메뉴) 에 해당함
$(this).each(function (idx, ele) {
...
// 이것은 그냥.. 이렇게 되야겠네요. this == $('.tabMenu') 입니다.
return this.each(function(idx, ele) {
...
};
말씀하신대로
tabMenu1 = {
$tabMenu : $tabMenu,
setSelectItemAt : setSelectItemAt
};
이기 때문에, tabMenu1.$tabMenu.on() .. 이렇게 호출할 수 있는 것이 맞습니다.
따라서 이경우에는 chaining 이 아닙니다. chaining 은 메소드가 자기 자신을 다시 반환함으로써 이어서 다른 함수를 계속 호출할 수 있도록 하는 것입니다.
$(selector).myTab().setBorder() 처럼 myTab() 안에서 object 자신인 $(selector) 를 반환함으로써 또 다시 setBorder() 를 호출할 수 있도록 하는 것입니다.
마찬가지로 setBorder()에서도 $(selector) 자신을 반환해서 다른 플러그인을 연속해서 호출 할 수 있도록 하는 것입니다. !-->!-->
약간 소스를 고쳐보면요..
- ul 태그에 탭 패널들을 감싸는 wrapper 의 ID 를 지정 (data-panel-wrapper="tabContent1")
- 각 탭 메뉴들에 연결되는 탭 패널들의 ID 를 지정 (data-panel="pan1" --> 클릭시 '#pan1' 을 선택)
- MyTab 함수에서 selector 를 클래스로 받게되면, 한페이지에 탭이 여러개 있어도 한번에 처리 가능
<ul class="tabMenu" data-panel-wrapper="tabContent1">
<li data-panel="pan1">탭 메뉴1</li>
<li data-panel="pan2">탭 메뉴2</li>
<li data-panel="pan3">탭 메뉴3</li>
<li data-panel="pan4">탭 메뉴4</li>
<li data-panel="pan5">탭 메뉴5</li>
</ul>
<div id="tabContent1">
<div id="pan1" class="tab-panel">탭 컨텐츠 1</div>
<div id="pan2" class="tab-panel">탭 컨텐츠 2</div>
<div id="pan3" class="tab-panel">탭 컨텐츠 3</div>
<div id="pan4" class="tab-panel">탭 컨텐츠 4</div>
<div id="pan5" class="tab-panel">탭 컨텐츠 5</div>
</div>
<script>
$(document).ready(function () {
MyTab('.tabMenu');
});
// 탭메뉴 기능 구현하기
function MyTab(selector) {
$(selector).each(function(idx, ele) {
// 탭 메뉴 레퍼 (UL)
let $tabMenu = $(ele);
// 각 메뉴들 (LI 태그)
let $menuItems = $tabMenu.find("li");
// 탭 패널들 (UL 태그의 'data-panel-wrapper' 속성을 읽어와 그 안의 '.tab-panel' 클래스들을 찾음)
let $tabPanels = $('#'+$tabMenu.data('panel-wrapper')).find('.tab-panel');
// 메뉴 클릭 이벤트 핸들러
function setSelectItem($item) {
$menuItems.removeClass('select');
$item.addClass('select');
$tabPanels.removeClass('select');
$tabPanels.eq($item.index()).addClass('select');
}
// 클릭 이벤트 등록
$menuItems.click(function () {
setSelectItem($(this));
});
});
}
</script>
첫번째 질문 부터
=======================
var tabMenu1 = tabMenu("#tabMenu1"); 여기서 tabMenu1라는 ID값을 변수에 넣어 초기화했는데요 왜 tabMenu("#tabMenu1")라는 값이 붙어야만 실행이 되는거죠?
===================
var 뒤에 붙은 tabMenu1은 그냥 변수입니다. 그냥 xx1이라고 바꾸어도 됩니다. (67번째 줄도)
#tabMenu1은 114번째 줄의 tabMenu1입니다. 이것을 둘다 yy2로 바꾸셔도 됩니다.
그리고 tabMenu는 함수명의 tabMenu이고..(66째줄)
67번째줄의 $tabMenu는 75번째줄의 변수입니다. zz3로 바꾸면
id=yy2를 tabMenu라는 함수로 처리한후에 xx1변수에 담아서 xx1안에 있는 변수 zz3를 선택하고 그것의 on event를 선택하는 것 같습니다.
JQeury가 어렵네요. ㅠㅠ
사용자 이벤트 처리를 할 수 있도록.. jQuery 플러그인 형태로 만들면..
<ul class="tabMenu" data-panel-wrapper="tabContent1">
<li data-panel="pan1">탭 메뉴1</li>
<li data-panel="pan2">탭 메뉴2</li>
<li data-panel="pan3">탭 메뉴3</li>
<li data-panel="pan4">탭 메뉴4</li>
<li data-panel="pan5">탭 메뉴5</li>
</ul>
<div id="tabContent1">
<div id="pan1" class="tab-panel">탭 컨텐츠 1</div>
<div id="pan2" class="tab-panel">탭 컨텐츠 2</div>
<div id="pan3" class="tab-panel">탭 컨텐츠 3</div>
<div id="pan4" class="tab-panel">탭 컨텐츠 4</div>
<div id="pan5" class="tab-panel">탭 컨텐츠 5</div>
</div>
<script>
(function($) {
// JQuery 플러그인에 등록
// - options: 사용자 지정 옵션
$.fn.myTab = function(options) {
// 옵션을 기본 설정과 병합
let settings = $.extend({
onBeforeTabChange : null,
onAfterTabChange : null,
}, options);
// 지정된 selector 에 해당하는 모든 elements 들을 순회
// jQuery chainning 을 위해 반환
return this.each(function() {
// $(this) 는 $(메뉴) 에 해당함
$(this).each(function (idx, ele) {
// 탭 메뉴 레퍼 (UL)
let $tabMenu = $(ele);
// 각 메뉴들 (LI 태그)
let $menuItems = $tabMenu.find("li");
// 탭 패널들 (UL 태그의 'data-panel-wrapper' 속성을 읽어와 그 안의 '.tab-panel' 클래스들을 찾음)
let $tabPanels = $('#' + $tabMenu.data('panel-wrapper')).find('.tab-panel');
// 메뉴 클릭 이벤트 핸들러
function setSelectItem($item) {
// onBeforeTabChange 가 옵션으로 설정되었다면 호출
if (settings.onBeforeTabChange) {
settings.onBeforeTabChange($item);
}
$menuItems.removeClass('select');
$item.addClass('select');
$tabPanels.removeClass('select');
let $clickedPanel = $tabPanels.eq($item.index());
$clickedPanel.addClass('select');
// onAfterTabChange 가 옵션으로 설정되었다면 호출
if (settings.onAfterTabChange) {
settings.onAfterTabChange($item, $clickedPanel);
}
}
// 클릭 이벤트 등록
$menuItems.click(function () {
setSelectItem($(this));
});
});
});
};
})(jQuery);
$(document).ready(function () {
$('.tabMenu').myTab({
// 탭이 클릭된 후 메뉴가 변경되기 바로 직전 호출
// - $menu : 클릭된 메뉴
onBeforeTabChange: function($menu) {
console.log('before tab change : ', $menu);
},
// 탭이 클릭된 후 메뉴가 변경된 바로 직후 호출
// - $menu : 클릭된 메뉴
// - $panel : 선택된 탭 패널
onAfterTabChange: function($menu, $panel) {
console.log('after tab change : ', $menu, $panel);
}
});
});
</script>
이런식으로 됩니다. 공부하시는데 도움이 되시라고 만들어봤습니다.
!-->1. $.fn.PLUGIN_NAME = function() {}; jQuery 플러그인 등록하는 방법입니다.
2. $.extend 는 object 들을 merge 하는 함수입니다. https://api.jquery.com/jquery.extend/
3. "아래 onbeforeTabChange가 호출된 이 후에 위에 if문이 호출되는겁니다."
그 아래에 있는 `onbeforeTabChange` 는 myTab 에 파라미터로 전달되는 인자입니다. 거기서 실행되는게 아니고. extend 함수에 의해서 settings 에 합쳐져서, 플러그인 내에서 호출이 되는거죠. 즉, 이벤트 처리루틴을 함수에 인자로 넘겨주는 것입니다.
간단한 코드로 설명드릴테니 아래를 천천히 읽어보세요.
아래와 같은 HTML 코드가 있다고 하고 코드로 설명을 드려봅니다.
<div id="article">
<h1>제목</h1>
<p>내용</p>
</div>
<ul>
<li class="lst">목록1</li>
<li class="lst">목록2</li>
<li class="lst">목록3</li>
</ul>
기본적인 jQuery 플러그인을 작성해보겠습니다. $(selector).printOut() 이라고 호출하면 selector 에 해당하는 HTML element 의 내용을 콘솔에 출력하는 것입니다.
<script>
(function($) {
// `printOut` 이라는 jQuery 플러그인 등록
$.fn.printOut = function() {
// HTML element 의 내용을 콘솔에 출력
console.log(this.html());
};
})(jQuery);
$(document).ready(function () {
// `#article` 의 내용을 출력합니다.
$('#article').printOut();
#('.lst').printOut(); // 첫번째 .lst 의 내용만 출력됨 T_T;;;
});
</script>
모든 .lst 에 대해서 동작하도록 수정해보겠습니다.
<script>
(function($) {
// `printOut` 이라는 jQuery 플러그인 등록
$.fn.printOut = function() {
// 아래의 this는 $('.lst') 와 같습니다.
// '.lst' 클래스를 갖는 element 들에 대해서 반복문을 돈다고 이해하시면 되겠습니다.
this.each(function(idx, ele) {
// 각 .lst ELEMENT 들에 대해서 내용을 화면에 출력
console.log($(ele).html());
}
};
})(jQuery);
$(document).ready(function () {
// 3개의 LI 의 내용들이 콘솔에 출력됩니다.
$('.lst').printOut();
});
</script>
만약, '.lst' 의 내용을 화면에 출력하고 이어서 다른 플러그인을 호출하고 싶다면 어떻게 하는지 해보겠습니다.
<script>
(function($) {
// `printOut` 이라는 jQuery 플러그인 등록
$.fn.printOut = function() {
// `return` 이 추가되었습니다.
// 여기서 return 을 하므로, 다음과 같은 호출이 가능합니다.
// $(selector).printOut().setBorder();
return this.each(function(idx, ele) {
console.log($(ele).html());
}
};
// 선택된 HTML Element 에 red border 를 설정하는 플러그인
$.fn.setBorder = function() {
return this.each(function (idx, ele) {
$(ele).css({'border': '1px solid red'});
});
};
})(jQuery);
$(document).ready(function () {
// 3개의 LI 의 내용들이 콘솔에 출력됩니다.
// 그리고 각 LI 에 border 가 red 로 설정됩니다.
$('.lst').printOut().setBorder();
});
</script>
<script>
(function($) {
$.fn.printOut = function() {
return this.each(function(idx, ele) {
console.log($(ele).html());
}
};
// options 를 파라미터로 받습니다.
$.fn.setBorder = function(options) {
// 기본 설정값은 'border_color' 가 'red' 로 되어있습니다.
// 이 설정을 파라미터로 넘어온 options 와 병합합니다.
// 즉, 기본값은 'red' 이지만 사용자가 options 를 통해 색을 변경할 수 있습니다.
let settings = $.extend({
border_color: 'red'
}, options);
return this.each(function (idx, ele) {
// `settings.border_color` 로 border 를 설정합니다.
$(ele).css({'border': '1px solid '+settings.border_color});
});
};
})(jQuery);
$(document).ready(function () {
// setBorder 플러그인에 {border_color: 'red'} 를 넘깁니다.
// 위의 setBorder(options) 의 `options` 가 {border_color: 'red'} 인거죠.
// 이렇게 하면, 화면에 LI 내용들이 3개 출력되고 각 LI 들에 파란색 border 가 생깁니다.
$('.lst').printOut().setBorder({border_color: 'blue'});
});
</script>
쉬운 예제로 설명드렸습니다. 찬찬히 보시면 아실 수 있을겁니다.
답변으로 드린 예제도 형식은 지금 설명드린 플러그인 작성법에 따른것이므로 이해하실 수 있을겁니다.
화이팅~