단비의 코딩 공부 blog

[Vanilla JS]study 16일차 - 웹 컨텐츠 제작 - 메인 메뉴 본문

javascript&jquery

[Vanilla JS]study 16일차 - 웹 컨텐츠 제작 - 메인 메뉴

황굽달 2023. 3. 24. 09:15

전체메뉴

1. 전체메뉴

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>JS - 메인 네비게이션</title>
        <link type="text/css" rel="stylesheet" href="common01.css" />
    </head>
    <body>
    	<header>
        	<nav class="tnav">
            	<ul>
                    <li><a href="#">탑메뉴1</a></li>
                    <li><a href="#">탑메뉴2</a></li>
                    <li><a href="#">탑메뉴3</a></li>
                    <li><a href="#">탑메뉴4</a></li>
                </ul>    
            </nav>
        	<h1>로고</h1>
            <!-- 메인네비게이션 전체묶음 -->
            <nav id="gnb">
            	<ul>
                    <li>
                        <!-- 메인메뉴 -->
                        <a href="#" class="mainnav">메인메뉴1</a>
                        <!-- 서브메뉴 -->
                    	<ul class="subnav">
                            <li><a href="#">하위메뉴1_1</a></li>
                            <li><a href="#">하위메뉴1_2</a></li>
                            <li><a href="#">하위메뉴1_3</a></li>
                            <li><a href="#">하위메뉴1_4</a></li>
                            <li><a href="#">하위메뉴1_5</a></li>
                            <li><a href="#">하위메뉴1_6</a></li>
                        </ul>
                    </li>
                    <li><a href="#" class="mainnav">메인메뉴2</a>
                    	<ul class="subnav">
                            <li><a href="#">하위메뉴2_1</a></li>
                            <li><a href="#">하위메뉴2_2</a></li>
                            <li><a href="#">하위메뉴2_3</a></li>
                            <li><a href="#">하위메뉴2_4</a></li>
                            <li><a href="#">하위메뉴2_5</a></li>
                            <li><a href="#">하위메뉴2_6</a></li>
                        </ul>
                    </li>
                    <li><a href="#" class="mainnav">메인메뉴3</a>
                    	<ul class="subnav">
                            <li><a href="#">하위메뉴3_1</a></li>
                            <li><a href="#">하위메뉴3_2</a></li>
                            <li><a href="#">하위메뉴3_3</a></li>
                            <li><a href="#">하위메뉴3_4</a></li>
                            <li><a href="#">하위메뉴3_5</a></li>
                            <li><a href="#">하위메뉴3_6</a></li>
                        </ul>
                    </li>
                    <li><a href="#" class="mainnav">메인메뉴4</a>
                    	<ul class="subnav">
                            <li><a href="#">하위메뉴4_1</a></li>
                            <li><a href="#">하위메뉴4_2</a></li>
                            <li><a href="#">하위메뉴4_3</a></li>
                            <li><a href="#">하위메뉴4_4</a></li>
                            <li><a href="#">하위메뉴4_5</a></li>
                            <li><a href="#">하위메뉴4_6</a></li>
                        </ul>
                    </li>
                    <li>
                        <a href="#" class="mainnav">메인메뉴5</a>
                    	<ul class="subnav">
                            <li><a href="#">하위메뉴5_1</a></li>
                            <li><a href="#">하위메뉴5_2</a></li>
                            <li><a href="#">하위메뉴5_3</a></li>
                            <li><a href="#">하위메뉴5_4</a></li>
                            <li><a href="#">하위메뉴5_5</a></li>
                            <li><a href="#">하위메뉴5_6</a></li>
                        </ul>
                    </li>
            	</ul>
                 <!-- 서브메뉴 배경 : 동적생성할 예정-->
                <div id="subbg"></div>      
            </nav>
        </header>
        <section></section>
        <footer></footer>
        <script src="common01.js"></script>
    </body>
</html>
/* base */
*{ padding: 0; margin: 0; font-size: 12px; color: #666666; }
li{ list-style: none; }
a{ text-decoration: none; }

/* layout */
header{ width: 1000px; height: 100px; margin: 0 auto; background-color: bisque; }
section{ width: 1000px; height: 900px; margin: 0 auto; background-color: lightblue; }
footer{ width: 1000px; height: 100px; margin: 0 auto; background-color: pink; }

.tnav{ width: 1000px; height: 30px; background-color: orange; }
header h1{ float: left; width: 150px; height: 70px; background-color: lightcyan; }
#gnb{ float: left; width: 850px; height: 70px; }

/* tnav */
.tnav ul{ float: right; }
.tnav li{ float: left; margin: 0 5px; line-height: 30px; }

/* gnb */
#gnb > ul > li{ 
	float: left; width: 20%; height: 70px; text-align: center; line-height: 69px; 
	position: relative; /* 자손인 subnav의 위치를 li기준에 맞추기 위해 */
}
#gnb .mainnav{
	display: block; width: 100%; height: 100%; 
	font-size: 16px; color: #333; font-weight: bold;
}
#gnb li:hover .mainnav{ color: red; }

/* 메인메뉴 활성화 */
#gnb .mainnav.active{ color: red; }

/* subnav */
.subnav{
	width: 100%; height: 0; overflow: hidden;
	line-height: 40px;
	position: absolute; /* 뒤에 보일 컨텐츠보다 화면 깊이상 앞에 보여야 함 */
	z-index: 1001; /* subbg보다 z-index수치가 높아야함 */
	top: 70px; left: 0;

	transition: 0.3s ease-in-out;
}
.subnav a:hover{ text-decoration: underline; }

#subbg{
	width: 100%; height: 0;
	background-color: rgba(0,255,0,0.5);
	position: absolute; top: 100px; left: 0;
	z-index: 1000; /* 서브메뉴보다 깊이상 아래 존재 */

	transition: 0.3s ease-in-out;
}

/* 활성화 처리 */
.subnav.active, #subbg.active{ height: 240px; }
//1. 문서객체 선택
const gnb = document.getElementById('gnb');
const mainnav = gnb.getElementsByClassName('mainnav');
const subnav = gnb.getElementsByClassName('subnav');


//2. subbg를 동적생성
const subbg = document.createElement('div');
subbg.setAttribute('id', 'subbg');

gnb.appendChild(subbg); //gnb의 마지막 자손으로 처리

//3. 이벤트로 받는 동일 명령이 많음 - 함수에 담기
activeFx = () => {  //활성 함수
    //subbg보이게 처리
    subbg.classList.add('active');

    for(let i=0;i<subnav.length;i++){
        subnav[i].classList.add('active');
    }
}

unactiveFx = () => {  //비활성 함수
    //subbg보이게 처리
    subbg.classList.remove('active');

    for(let i=0;i<subnav.length;i++){
        subnav[i].classList.remove('active');
    }

    //메인메뉴 활성제거
    mainnavdefalut();
}

//메인메뉴 활성을 모두 제거
mainnavdefalut = () => {
    for(let j=0;j<mainnav.length;j++){
        mainnav[j].classList.remove('active');
    }
}

//4. 마우스 이벤트
//4-1. mouseenter
gnb.addEventListener('mouseenter', activeFx);
//4-1. mouseleave
gnb.addEventListener('mouseleave', unactiveFx);

//5. 웹접근성 - 키보드 접근성
//5-1. 첫번째 메인메뉴에 초점받았을 때
mainnav[0].addEventListener('focus', activeFx);
//5-2. 모든 메인메뉴에 초점을 받으면 해당 메인메뉴활성
for(let i=0;i<mainnav.length;i++){
    mainnav[i].addEventListener('focus', function(){
        mainnavdefalut();  //전부 제거 후
        this.classList.add('active'); //이벤트 받은 대상만 active처리
    });
}

//5-3. 마지막 하위리스트의 a태그에서 탭키를 눌렀을 때 모든 것이 비활성화
const lastNum = subnav.length - 1;  //마지막 인덱스 번호를 담는 변수
const lastLink = subnav[lastNum].lastElementChild.firstElementChild;

lastLink.addEventListener('keydown', function(e){
    if(e.keyCode == 9){  //tab키를 눌렀을 때
        if(!e.shiftKey){  //쉬프트키는 누르지 않았다면
            unactiveFx();
            mainnavdefalut();
        }  
    }
});

//5-4. 첫번째 메인메뉴에서 shift+tab키를 눌렀을 때 모두 비활성화
mainnav[0].addEventListener('keydown', function(e){
    if(e.keyCode == 9){  //tab키를 눌렀을 때
        if(e.shiftKey){  //쉬프트키를 눌렀다면
            unactiveFx();
            mainnavdefalut();
        }  
    }
});

//5-5. 각각 하위메뉴의 마지막 a태그에 초점을 받았을 해당 메인메뉴 활성
for(let i=0;i<subnav.length;i++){
    const a = subnav[i].lastElementChild.firstElementChild;

    a.addEventListener('focus', function(){
        mainnavdefalut();  //모든 메인메뉴 active제거 후
        this.parentNode.parentNode.previousElementSibling.classList.add('avtive');
    });
}

2. 각각메뉴

각각메뉴

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>JS - 메인 네비게이션</title>
        <link type="text/css" rel="stylesheet" href="common02.css" />
    </head>
    <body>
    	<header>
        	<nav class="tnav">
            	<ul>
                    <li><a href="#">탑메뉴1</a></li>
                    <li><a href="#">탑메뉴2</a></li>
                    <li><a href="#">탑메뉴3</a></li>
                    <li><a href="#">탑메뉴4</a></li>
                </ul>    
            </nav>
        	<h1>로고</h1>
            <!-- 메인메뉴 전체 묶음 -->
            <nav id="gnb">
            	<ul>
                    <li>
                        <!-- 메인메뉴 -->
                    	<a href="#" class="mainnav">메인메뉴1</a>
                        <!-- 서브메뉴 -->
                    	<ul class="subnav">
                            <li><a href="#">하위메뉴1_1</a></li>
                            <li><a href="#">하위메뉴1_2</a></li>
                            <li><a href="#">하위메뉴1_3</a></li>
                            <li><a href="#">하위메뉴1_4</a></li>
                            <li><a href="#">하위메뉴1_5</a></li>
                            <li><a href="#">하위메뉴1_6</a></li>
                        </ul>
                    </li>
                    <li><a href="#" class="mainnav">메인메뉴2</a>
                    	<ul class="subnav">
                            <li><a href="#">하위메뉴2_1</a></li>
                            <li><a href="#">하위메뉴2_2</a></li>
                            <li><a href="#">하위메뉴2_3</a></li>
                            <li><a href="#">하위메뉴2_4</a></li>
                            <li><a href="#">하위메뉴2_5</a></li>
                            <li><a href="#">하위메뉴2_6</a></li>
                        </ul>
                    </li>
                    <li><a href="#" class="mainnav">메인메뉴3</a>
                    	<ul class="subnav">
                            <li><a href="#">하위메뉴3_1</a></li>
                            <li><a href="#">하위메뉴3_2</a></li>
                            <li><a href="#">하위메뉴3_3</a></li>
                            <li><a href="#">하위메뉴3_4</a></li>
                            <li><a href="#">하위메뉴3_5</a></li>
                            <li><a href="#">하위메뉴3_6</a></li>
                        </ul>
                    </li>
                    <li><a href="#" class="mainnav">메인메뉴4</a>
                    	<ul class="subnav">
                            <li><a href="#">하위메뉴4_1</a></li>
                            <li><a href="#">하위메뉴4_2</a></li>
                            <li><a href="#">하위메뉴4_3</a></li>
                            <li><a href="#">하위메뉴4_4</a></li>
                            <li><a href="#">하위메뉴4_5</a></li>
                            <li><a href="#">하위메뉴4_6</a></li>
                        </ul>
                    </li>
                    <li><a href="#" class="mainnav">메인메뉴5</a>
                    	<ul class="subnav">
                            <li><a href="#">하위메뉴5_1</a></li>
                            <li><a href="#">하위메뉴5_2</a></li>
                            <li><a href="#">하위메뉴5_3</a></li>
                            <li><a href="#">하위메뉴5_4</a></li>
                            <li><a href="#">하위메뉴5_5</a></li>
                            <li><a href="#">하위메뉴5_6</a></li>
                        </ul>
                    </li>
            	</ul>        
            </nav>
        </header>
        <section></section>
        <footer></footer>
        <script src="common02.js"></script>
    </body>
</html>
/* base */
*{ padding: 0; margin: 0; font-size: 12px; color: #666666; }
li{ list-style: none; }
a{ text-decoration: none; }

/* layout */
header{ width: 1000px; height: 100px; margin: 0 auto; background-color: lightblue; }
section{ width: 1000px; height: 900px; margin: 0 auto; background-color: antiquewhite; }
footer{ width: 1000px; height: 100px; margin: 0 auto; background-color: lightcyan; }

.tnav{ width: 1000px; height: 30px; background-color: orange; }
header h1{ float: left; width: 150px; height: 70px; background-color: bisque; }
#gnb{ float: left; width: 850px; height: 70px; }

/* tnav */
.tnav ul{ float: right; }
.tnav li{ float: left; margin: 0 5px; line-height: 30px; }

/* gnb */
#gnb > ul > li{ float: left; width: 20%; height: 70px; text-align: center; line-height: 70px; position: relative; } /* 하위메뉴 위치 컨트롤 */
#gnb > ul > li > a{ display: block; width: 100%; height: 100%; font-size: 16px; font-weight: bold; color: #333333; }
#gnb > ul > li:hover > a{ color: #FF0000; }
/* 제이쿼리에서 하위메뉴에 오버시 메인메뉴에도 색상이 변경되게 처리 */
#gnb > ul > li > a.active{ color: #FF0000; }

.subnav{ 
    position: absolute; top: 60px; left: 0; width: 170px; height: 0; overflow: hidden; line-height: 40px; box-sizing: border-box; background-color: #FFFFFF; 
    z-index: 1000; /* 메인이미지 슬라이더보다 위에 올라오게 처리하기 위해 z-index 사용 */

    transition: 0.3s ease-in-out;
}

/* 활성화 */
.subnav.active{ height: 240px; }
//1.문서객체 선택
const mainnav = document.querySelectorAll('#gnb .mainnav');
const subnav = document.querySelectorAll('#gnb .subnav');

//2. 마우스이벤트 - 메인메뉴에 마우스를 올렸을 때 활성
for(let i=0; i<mainnav.length;i++){
    mainnav[i].addEventListener('mouseenter', function(){
        //this : 메인메뉴
        this.nextElementSibling.classList.add('active');
        
        //부모인 li태그에서 마우스가 벗어났을 때 비활성
        this.parentNode.addEventListener('mouseleave', function(){
            //this : 부모인 li태그
            this.firstElementChild.classList.remove('active');
            this.lastElementChild.classList.remove('active');
        });
    });

    //3. 웹접근성
    //3-1. 각각의 메인메뉴에 초점받으면 활성화
    mainnav[i].addEventListener('focus', function(){
        //모든 건 비활성 후
        //모든 하위메뉴의 a태그에 초점 비활성
        for(let j=0;j<mainnav.length;j++){
            mainnav[j].classList.remove('active');
            subnav[j].classList.remove('active');
            
            const a = subnav[j].getElementsByTagName('a');
            
            for(let k=0;k<a.length;k++){
                a[k].setAttribute('tabindex','-1'); //초점받지 못하게 처리
            }
        }

        //초점받은 대상만 활성
        this.classList.add('active');
        this.nextElementSibling.classList.add('active');

        //초점받은 메인메뉴의 하위메뉴 a만 초점 활성
        const activeLink = this.nextElementSibling.getElementsByTagName('a')
        
        for(let j=0;j<activeLink.length;j++){
            activeLink[j].setAttribute('tabindex', 0); //초점 활성
        } 
    });
}

//3-2. 첫번째 메인메뉴에서 shift+tab누르면 비활성 처리
mainnav[0].addEventListener('keydown', function(e){
    if(e.keyCode == 9){
        if(e.shiftKey){
            this.classList.remove('active');
            this.nextElementSibling.classList.remove('active');
        }
    }
});

//3-3. 마지막 하위메뉴 a태그에서 tab키를 눌렀을 때 비활성
const lastNum = subnav.length -1;
const subnavLast = subnav[lastNum].lastElementChild.firstElementChild;
subnavLast.addEventListener('keydown', function(e){
    if(e.keyCode == 9){
        if(!e.shiftKey){
            mainnav[lastNum].classList.remove('active');
            subnav[lastNum].classList.remove('active');
        }
    }
});