플러그인을 쓰지 않고 구현하는 tree menu
See the Pen tree menu with custom checkbox by publisher.kim (@publisherkim) on CodePen.
html
<!-- 첫번째 treebox -->
<div class="treebox">
<!-- first depth -->
<ul class="fdepth">
<li>
<button class="btn_tree" title="트리열기"></button>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01"><label for="cbx01">전체</label></span>
</span>
<!-- second depth -->
<ul class="sdepth">
<li>
<button class="btn_tree" title="트리열기"></button>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01_1"><label for="cbx01_1">메뉴1</label></span>
</span>
<!-- third depth -->
<ul class="tdepth">
<li>
<button class="btn_tree" title="트리열기"></button>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01_1_1"><label for="cbx01_1_1">메뉴1_1</label></span>
</span>
<!-- fourth depth -->
<ul class="fodepth">
<li>
<button class="btn_tree" title="트리열기"></button>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01_1_1_1"><label for="cbx01_1_1_1">메뉴1_1_1</label></span>
</span>
<!-- fifth depth -->
<ul class="fidepth">
<li>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01_1_1_1_1"><label for="cbx01_1_1_1_1">메뉴1_1_1_1</label></span>
</span>
</li>
<li>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01_1_1_1_2"><label for="cbx01_1_1_1_2">메뉴1_1_1_2</label></span>
</span>
</li>
</ul>
</li>
</ul>
</li>
<li>
<button class="btn_tree" title="트리열기"></button>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01_1_2"><label for="cbx01_1_2">메뉴1_2</label></span>
</span>
<!-- fourth depth -->
<ul class="fodepth">
<li>
<button class="btn_tree" title="트리열기"></button>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01_1_2_1"><label for="cbx01_1_2_1">메뉴1_2_1</label></span>
</span>
<!-- fifth depth -->
<ul class="fidepth">
<li>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01_1_2_1_1"><label for="cbx01_1_2_1_1">메뉴1_2_1_1</label></span>
</span>
</li>
<li>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01_1_2_1_2"><label for="cbx01_1_2_1_2">메뉴1_2_1_2</label></span>
</span>
</li>
</ul>
</li>
<li>
<button class="btn_tree" title="트리열기"></button>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01_1_2_2"><label for="cbx01_1_2_2">메뉴1_2_2</label></span>
</span>
<!-- fifth depth -->
<ul class="fidepth">
<li>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01_1_2_2_1"><label for="cbx01_1_2_2_1">메뉴1_2_2_1</label></span>
</span>
</li>
<li>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01_1_2_2_2"><label for="cbx01_1_2_2_2">메뉴1_2_2_2</label></span>
</span>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>
<button class="btn_tree" title="트리열기"></button>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01_2"><label for="cbx01_2">메뉴2</label></span>
</span>
<!-- third depth -->
<ul class="tdepth">
<li>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01_2_1"><label for="cbx01_2_1">메뉴2_1</label></span>
</span>
</li>
<li>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01_2_2"><label for="cbx01_2_2">메뉴2_2</label></span>
</span>
</li>
<li>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx01" id="cbx01_2_3"><label for="cbx01_2_3">메뉴2_3</label></span>
</span>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<!-- 두번째 treebox -->
<div class="treebox">
<!-- first depth -->
<ul class="fdepth">
<li>
<button class="btn_tree" title="트리열기"></button>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx02" id="cbx02"><label for="cbx02">전국</label></span>
</span>
<!-- second depth -->
<ul class="sdepth">
<li>
<button class="btn_tree" title="트리열기"></button>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx02" id="cbx02_1"><label for="cbx02_1">서울</label></span>
</span>
<!-- third depth -->
<ul class="tdepth">
<li>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx02" id="cbx02_1_1"><label for="cbx02_1_1">종로구</label></span>
</span>
</li>
<li>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx02" id="cbx02_1_2"><label for="cbx02_1_2">강남구</label></span>
</span>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<!-- 단일 chekbox 있는 treebox -->
<div class="treebox">
<ul class="fdepth"><!-- first depth -->
<li>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx03" id="cbx03_1"><label for="cbx03_1">2022년</label></span>
</span>
</li>
<li>
<span class="chk">
<span class="cbx"><input type="checkbox" name="cbx03" id="cbx03_2"><label for="cbx03_2">2021년</label></span>
</span>
</li>
</ul>
</div>
css
/* treebox */
.treebox{border:1px solid #ddd; padding:20px; margin-left:20px; margin-top: 20px; max-width: 400px; box-sizing: border-box;}
.treebox .btn_tree{display: inline-block; width: 16px; height: 16px; border: 0; background: url(https://umings.github.io/images/i_tree_off.png) no-repeat center; vertical-align: -1px; margin-right: 5px; cursor: pointer;}
.treebox .btn_tree.on{background: url(https://umings.github.io/images/i_tree_on.png) no-repeat center; }
.treebox li .chk{padding: 3px 0; margin-left: 16px;}
.treebox li .btn_tree + .chk{margin-left: 0;}
.treebox .fdepth > li > .chk{margin-left: 0;}
.treebox .sdepth li{background: url(https://umings.github.io/images/i_line2.png) no-repeat left 8px top -9px, url(https://umings.github.io/images/i_line3.png) repeat-y left 8px top; padding-left: 16px;}
.treebox .sdepth li:last-of-type{background: url(https://umings.github.io/images/i_line.png) no-repeat left 8px top -8px;}
.treebox ul{display: none;}
.treebox .fdepth{display: block;}
/* custom checkbox*/
.treebox span.chk {display: inline-block;}
.treebox .chk input {opacity: 0; position: absolute;}
.treebox .chk > span {display: inline-block;}
.treebox .chk > span label {display: inline-block;position: relative;line-height: 1;cursor: pointer; padding-left:1.2em; }
.treebox .chk .cbx label::before {content: '';position: absolute;left: 0;top: 1px;width:15px;height:15px;border: 1px solid #c6c6c6;background: #fff;border-radius: 3px;margin-right: 0;vertical-align: bottom;cursor:pointer;}
.treebox .chk .cbx input:checked + label::before {background: #0c76ce; border: 1px solid #0c76ce;}
.treebox .chk .cbx input:checked + label::after{content:'';position:absolute;left: 5px;top: 3px;width:5px;height:8px;border-width:0 2px 2px 0;border-style:solid;border-color:#fff;transform:rotate(45deg);}
js *jquery 필요
$(function(){
// 트리 열고닫기
$(".treebox .btn_tree").click(function(){
if($(this).hasClass("on")){
$(this).removeClass("on");
$(this).attr("title","트리 열기")
$(this).parent().children("ul").hide();
}else{
$(this).addClass("on");
$(this).attr("title","트리 닫기")
$(this).parent().children("ul").show();
}
return false;
})
// parents() selector로 잡히는 모든 상위 요소를 반환한다.
// closest() selector로 잡히는 상위 요소중 가장 근접한 하나를 반환한다.
$(".treebox .chk input").click(function(){
var checked = $(this).is(':checked'); // 체크 박스 클릭 후 상태
var checkId = $(this).attr("id"); // 체크 박스 아이디
// 1. 체크 후 처리
if(checked) {
// 하위 체크박스 전체 체크
$(this).parent().parent().next().find("[type='checkbox']").prop('checked', true);
var parentTrue = function(id) {
var lastIndex = id.lastIndexOf("_"); // 마지막 '_' 언더바가 있는 인덱스 값 호출
var parentId = id.substring(0, lastIndex); // 파라미터로 받아온 아이디에서 마지막 '_' 언더바까지 자른 아이디
var emptyList = []; // 체크를 위한 임시 배열
var emptyNum = 1; // 체크를 위한 첫번째 이름
var elemId = "#"+parentId+"_"+emptyNum; // 체크박스 아이디 초기화 1번부터 시작
// 부모 체크박스 아이디 체크 (재귀 함수를 사용하기에 마지막에는 이름이 공백으로 나온다 / 스크립트 에러 방지)
if(parentId != '') {
// 아이디값에 1씩 추가하여 실제 태그가 있을때 까지 emptyList에 추가
// #cbx01_1 , #cbx01_2 , #cbx01_3
while($(elemId).length) {
emptyList.push(elemId);
emptyNum++; // 1씩 추가
elemId = "#"+parentId+"_"+emptyNum; // 아이디 추출
}
// 재귀함수 호출 구분 값
var has = true;
// 배열안에 체크박스 아이디를 불러와 한개라도 체크되지 않는다면 그대로 종료
emptyList.forEach(function(id) {
if(!$(id).is(":checked")) {
has = false;
return false;
}
});
// 체크박스가 모두 체크되어 있다면 부모 체크박스 체크 후 재귀함수 호출
if(has) {
$("#"+parentId).prop("checked", true);
parentTrue(parentId);
}
}
}
parentTrue(checkId);
}
// 2. 체크 해제 후 처리
if(!checked) {
// 하위 체크박스 전체 해제
$(this).parent().parent().next().find("[type='checkbox']").prop('checked', false);
var parentFalse = function(id) {
var lastIndex = id.lastIndexOf("_"); // '_' 마지막 언다바를 기준으로 인덱스 호출
var parentId = id.substring(0, lastIndex); // 인덱스 까지 문자 호출
if(parentId != '' && $("#" + parentId).length) {
$("#" + parentId).prop('checked', false); // 상위 부모 체크박스 비활성화
parentFalse(parentId); // 재귀함수 - 메소드 재호출
}
}
parentFalse(checkId);
}
});
})
728x90
'퍼블리싱 > HTML | CSS | Javascript' 카테고리의 다른 글
swiper slider with background scale animation (0) | 2023.07.12 |
---|---|
랜덤으로 순서가 바뀌는 slider (+with video), 플러그인 x (0) | 2023.07.12 |
fullpage.js 기본 소스 (0) | 2023.06.15 |
DOM 변경 감지해서 이벤트 발생 (0) | 2023.06.12 |
head fixed table with custom scrollbar (0) | 2023.05.18 |