본문으로 바로가기

1단 메뉴 jQuery Study #1

category Code Lab 2016. 6. 15. 10:52

1단 메뉴 제이쿼리 스터디 단계별 학습 #1

이 글에서는 제이쿼리 그리고 자바스크립트의 생성자함수 및 프로토타입을 이용하여 심플한 1단 메뉴를 구현해 보는 시간을 가져보겠습니다.

다음 단계별 학습 #2를 통해서는 이 1단 메뉴를 플러그인 타입으로 리팩토링해 보도록 하겠습니다.




HTML

간단한 1단 메뉴를 위해 다음과 같은 마크업을 작성합니다.

html
<div class="bar-menu" id="barMenu1">
    <ul class="menu-body">
        <li>MENU 01</li>
        <li>MENU 02</li>
        <li>MENU 03</li>
        <li>MENU 04</li>
        <li>MENU 05</li>
    </ul>
    <div class="bar"> </div>
</div>



CSS

1단 메뉴에 대한 스타일시트는 다음과 같이 준비합니다.

css
* { padding:0; margin:0; }
body{ font-size:9pt; }
#barMenu1 { position:relative; left:100px; top:100px; width:450px; overflow: hidden; }
.bar-menu { position:relative; height:50px; cursor:pointer; }
.bar-menu ul.menu-body { position:relative; list-style: none; height:100%; }
.bar-menu ul.menu-body li {
    height:20px; padding:10px; margin-left:10px; float:left;
    line-height:20px; vertical-align:middle; border:2px solid #93b0bc;
    display:inline-block; border-radius: 10px;
}
/* 선택 메뉴 아이템 스타일 */
.bar-menu ul.menu-body li.select { background-color: #bddeea; }
/* 오버 메뉴 아이템 스타일 */
.bar-menu ul.menu-body li.over { background-color:#eee; }
.bar-menu .bar { width:0; height:5px; background-color: #468ebc; position: absolute; left:0; bottom:0; }



JavaScript

다음의 코드에는 사용자 이벤트를 정의하는 방법을 포함하고 있습니다.

콘솔창에서 그 결과를 확인하실 수 있습니다.

javascript
function BarMenu(selector) {
    // 프로퍼티 생성
    this.$barMenu = null;
    this._$menuBody = null;
    this._$menuItems = null;
    this._$overItem = null;
    this._$bar = null;

    // 선택 메뉴 아이템
    this.$selectItem = null;

    this._init(selector);
    this._initEvent();
}

BarMenu.prototype = {
    // 요소 초기화
    "_init" : function (selector) {
        this.$barMenu = $(selector);
        this._$menuBody = this.$barMenu.find('.menu-body');
        this._$menuItems = this._$menuBody.find('li');
        this._$bar = this.$barMenu.find('.bar');
    },
    
    // 이벤트 초기화
    "_initEvent" : function () {
        var _self = this;
        
        // 오버 메뉴 및 선택(클릭한)메뉴 이벤트 호출
        this._$menuItems.on('mouseenter click', function (e) {
            var $this = $(this);
            if(e.type == 'mouseenter') {
                _self._setOverMenuItem($this);
            } else if(e.type == 'click') {
                _self.setSelectMenuItem($this);
            }
        });
        
        // 전체 메뉴 영역을 벗어난 경우
        this.$barMenu.on('mouseleave', function () {
            var $this = $(this);
            
            // 기존 오버 메뉴아이템이 있는 경우 제거
            _self._removeOverItem($this);
            
            // 기존 선택한 메뉴아이템이 있는 경우 선택처리
            _self._reSelectMenuItem();
            
        });
        
    },
    
    // 오버 메뉴아이템 처리하기
    "_setOverMenuItem" : function ($item) {

        // 기존 오버되어 있는 아이템이 있다면 over 스타일을 제거
        if(this._$overItem) {
            this._$overItem.removeClass('over');
        }

        // 신규 오버 메뉴아이템이 선택한 메뉴아이템과 같지 않은 경우에만 메뉴아이템 스타일 적용하기
        // 선택 메뉴 아이템 인덱스 값 구하기
        var selectIndex = -1;
        if (this.$selectItem != null) {
            selectIndex = this.$selectItem.index();
        }

        // 신규 오버 메뉴아이템 인덱스 값과 선택한 메뉴아이템의 인덱스 값을 비교
        if ($item.index() != selectIndex) {
            this._$overItem = $item;
            this._$overItem.addClass('over');
        } else {
            this._$overItem = null;
        }
 
        // 메뉴바 이동
        this._moveBar($item);
    },

    // 전체 메뉴 영역 벗어날 때 오버 효과 제거
    "_removeOverItem" : function () {
        if(this._$overItem) {
            this._$overItem.removeClass('over');
        }
        this._$overItem = null;
        this._moveBar(null);
    },
    
    // 이동 메뉴 효과
    "_moveBar" : function ($item, animation) {
        var left = -100,
            width = 0;

        if ($item != null) {
            left = $item.position(true).left + parseInt($item.css('margin-left'));
            width = $item.outerWidth();
        }

        if(animation == false) {
            // 애니메이션 없이 바로 이동
            this._$bar.css({
                'left': left,
                'width' : width
            })
        } else {
            // 애니메이션 이동
            this._$bar
                .stop()
                .animate({
                    'left': left,
                    'width': width
                }, 300)
        }
    },

    // 선택(클릭) 메뉴 아이템 처리
    'setSelectMenuItem' : function ($item, aniamtion) {
        var $oldItem = this.$selectItem;

        // 기존에 선택한 메뉴가 있는 경우 처리
        if(this.$selectItem) {
            this.$selectItem.removeClass('select');
        }

        this.$selectItem = $item;
        this.$selectItem.addClass('select');

        // 메뉴바 이동
        this._moveBar($item, aniamtion);

        // 사용자 정의 이벤트 발생(호출)
        this._dispatchSelectEvent($oldItem, $item);
    },
    
    // 기존 선택한 메뉴아이템이 있는 경우 선택 처리
    "_reSelectMenuItem" : function () {
        if(this.$selectItem) {
            this._moveBar(this.$selectItem);
        }
    },

    // 메뉴아이템이 선택된 상태에서 시작하도록 설정하는 경우
    'setSelectMenuItemAt' : function (index, animation) {
        var target = this._$menuItems.eq(index);
        this.setSelectMenuItem(target, animation);
    },
    
    // 사용자 정의 이벤트 발생
    "_dispatchSelectEvent" : function ($oldItem, $newItem) {
        var customEvent = jQuery.Event('selected');
        customEvent.$oldItem = $oldItem;
        customEvent.$newItem = $newItem;
        this.$barMenu.trigger(customEvent);
    }

};


$(function () {
    var barMenu = new BarMenu('#barMenu1');
    // 메뉴아이템 선택 설정
    barMenu.setSelectMenuItemAt(2, false);

    // 사용자 정의 이벤트
    // 위에서 정의한 select 이벤트 리스너 등록하기
    barMenu.$barMenu.on('selected', function (e) {
        var oldIndex = -1;
        if (e.$oldItem) {
            oldIndex = e.$oldItem.index();
        }

        console.log('old = ' + oldIndex + ', new = ' + e.$newItem.index());
    });
});



Result View

See the Pen 1단메뉴 #1 by jaeheekim (@jaehee) on CodePen.





Jaehee's WebClub