워드프레스 테마 만들기: 사이드 네비게이션 (2)

in #kr-dev7 years ago

이전 포스트에서는 네비게이션을 만드는 Walker를 살펴봤습니다.

종류별로 아이콘 만들기

이제는 종류별로 아이콘을 붙이기 위해 워커의 start_el()을 개조합니다. Font Awesome 4.7.0를 사용했습니다. Font Awesome의 CDN을 cdnjs에서 찾아 CSS에 추가했습니다.

아이콘은 Font Awesome Icon에서 찾아볼 수 있습니다.

다음 내용을 start_el()에 추가했습니다.

if ( in_array( 'front-item', $classes ) ) :
  if ( in_array( 'menu-item-object-custom' , $classes ) ) :
    $item_icon = "fa-link";
  elseif ( in_array( 'menu-item-object-post' , $classes ) ) :
    $item_icon = "fa-file-text-o";
  elseif ( in_array( 'menu-item-object-page' , $classes ) ) :
    $item_icon = "fa-file-o";
  elseif ( in_array( 'menu-item-object-category' , $classes ) ) :
    $item_icon = "fa-list";
  endif;
else :
  $item_icon = "";
endif;

$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
// 아이콘 추가
$item_output .= '<i class="fa ' . $item_icon . '" aria-hidden="true"></i>';
$item_output .= $args->link_before . $title . $args->link_after;
$item_output .= '</a>';
$item_output .= $args->after;

서브메뉴 아코디언으로 만들기

start_elstart_lvl를 손봐서 서브메뉴를 아코디언으로 만드려고 합니다.

아코디언 구조

아코디언 메뉴는 .accordion클래스 아래에 .accordion-header.accordion-body를 두어 자바스크립트를 이용해 제어합니다. 제가 만드려고 하는 구조는 대략 이렇습니다.

<ul class="accordion">
  <li><a>메뉴 1</a></li>
  <li>
    <a class="accordion-header">메뉴 2</a>
    <ul class="accordion-body">
      <li><a>메뉴 2-1</a></li>
      <li><a>메뉴 2-2</a></li>
    </ul>
  </li>
  <li>
    <a class="accordion-header">메뉴 3</a>
    <ul class="accordion-body">
      <li><a>메뉴 3-1</a></li>
      <li><a>메뉴 3-2</a></li>
    </ul>
  </li>
</ul>

원래 숨겨져 있는 .accordion-body.accordion-header를 누르면 펼쳐집니다. .accordion 아래 들어있는 다른 .accordion-body들은 숨깁니다.

네비게이션 워커

start_lvl.accordion-body.accordion 클래스를 담아둡니다. .accordion은 서브 메뉴에 있는 하위 아코디언 메뉴를 클릭했을 때 부모 아코디언까지 닫이버리는 오작동을 피하기 위해 추가하기 위한 것 입니다.

<?php
public function start_lvl( &$output, $depth = 0, $args = array() ) {
  $classes = array(
    'sub-menu',
    "sub-menu-$depth",
    'accordion-body',
    'accordion',
  );
  $class_names = join( ' ', apply_filters( 'nav_menu_submenu_css_class', $classes, $args, $depth ) );
  $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
  $output .= "<ul$class_names>";
}

자바스크립트

문서를 로드한 후 .accordion-header 클래스의 요소에 드롭다운 아이콘을 추가합니다. 아이콘은 material icons에서 제공하는 것을 이용했습니다. 이 함수는 jQuery 기반으로 작성되었습니다.

var $document = $(document);
var $accordion_header = $('.accordion-header');

$document.ready(function(){
  html = $accordion_header.html();
  html += '<i class="accordion-icon material-icons right">arrow_drop_down</i>';
  $accordion_header.html(html);
});

이 아이콘은 활성화 되어있을 때 뒤집힙니다. 아코디언 헤더(.accordion-header)를 눌러 활성화 시키는 경우 해당 요소는 .accordion-active를 새로 얻도록 클릭 이벤트를 작성할 것입니다. 스타일을 이렇게 작성할 수 있습니다.

.accordion-header .accordion-icon {
  transition: transform .4s;
}
.accordion-header.accordion-active .accordion-icon {
  transform: rotate(180deg);
}

클릭 이벤트 를 작성합니다.

$accordion_header.click(function() {
  var $this = $(this);
  var $body = $this.next('.accordion-body');
  var $root = $this.closest('.accordion');
  var $others = $root.find($accordion_header).not($this);

  $others.next('.accordion-body').slideUp(200);
  $others.removeClass('accordion-active');
  $this.toggleClass('accordion-active');
  $body.slideToggle(200);
});

jQuery의 몇 가지 함수를 알아야 이 스크립트를 이해하기 편합니다. 우선 $( A ).next( B )는 A 선택자 바로 다음에 오는 B선택자 요소를 가져옵니다. $body의 경우 헤더요소 바로 뒤에 있는 몸통 요소를 불러오게 됩니다. $( A ).closest( B )은 A요소와 가장 가까운 B 부모를 가져옵니다. $root는 한 아코디언으로 묶인 헤더와 몸통을 가져오기 위한 것입니다. $( A ).find( B )는 A를 부모로 가진 B 선택자를 가져옵니다. .not( C )를 붙이면 선택된 것 중 C를 제외합니다.

이제 동작 부분입니다. 처음, .slideUp(200)으로 선택한 요소를 제외한 나머지 몸통을 슬라이드 0.2초 동안 애니메이션으로 숨깁니다. 그리고 .accordion-active 클래스가 있다면 제거하죠. 다음에는 toggleClass( A )를 이용해 A가 있다면 지우고, 없다면 추가하도록 만듭니다. 마지막으로 slideToggle(200)을 이용해 선택한 요소 바로 다음의 몸통을 열려있으면 닫고 닫혀있으면 열도록 합니다.

결과

soma0sd.local_.png

실제 동작은 제가 작성한 CodePen에서 확인하실 수 있습니다.