Vue.js 3 & NodeJS/Vue 3

Vue CLI 부트스크랩 5 내비게이션 바 2 - Vue CLI Bootstrap 5 Navbar Collapse

carrotweb 2022. 2. 14. 00:30
728x90
반응형

이어서 모바일에서는 내비게이션 바를 감추고 보여주는 Toggle(토글) 버튼(3개의 선으로 되어 있어 이미지로 햄버거 버튼이라고도 합니다.)을 생성하겠습니다.

1. C:\workspaces\nodeserver\testvue\src\App.vue 파일을 오픈합니다.

내비게이션 바에 brand(브랜드)인 <router-link> 다음에 <button> 태그를 추가합니다.

<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarContent">
	<span class="navbar-toggler-icon"></span>
</button>

<button> 태그의 class에 .navbar-toggler가 추가되어야 합니다.

<nav> 태그의 class에 있는 navbar-expand{-sm|-md|-lg|-xl|-xxl}를 기준으로 웹 브라우저의 가로 화면 크기가 설정된 크기보다 작으면 <button> 태그가 노출되고 크면 <button> 태그가 비노출됩니다. 즉, 모바일 사이즈에서만 <button> 태그가 노출됩니다.

<span> 태그의 class인 .navbar-toggler-icon은 SVG(Scalable Vector Graphics - 확장 가능한 벡터 그래픽)로 3개의 선으로 되어 있습니다.

Collapse(콜랩스)

Collapse(콜랩스)는 클래스와 JavaScript를 사용하여 콘텐츠를 노출(펼쳐짐) 시키거나 비노출(접혀짐) 시킬 수 있습니다. 즉, 노출(표시) 방식을 전환합니다.

Collapse(콜랩스)는 <button> 태그와 <a> 태그에 Toggle(토글) 되는 콘텐츠와 매핑되어 트리거로 사용됩니다. 콘텐츠가 노출(펼쳐짐) 되면 콘텐츠의 height가 0에서 콘텐츠의 크기로 점점 커지고 비노출(접혀짐) 되면 콘텐츠의 height가 콘텐츠의 크기에서 0으로 점점 작아지면서 애니메이션 처리됩니다.

data-bs-toggle에는 Toggle(토글) 방식을 설정합니다.

Toggle(토글) 방식에는 collapse(콜랩스), dropdown(드롭다운), tooltip(툴팁) 등이 있습니다.

data-bs-target에는 노출(펼쳐짐) 되거나 비 노출(접혀짐) 되는 콘텐츠의 id를 적용합니다. 콘텐츠의 id 앞에 '#'를 붙여줍니다.

data-bs-toggle와 data-bs-target는 항상 같이 적용되어야 합니다.

Bootstrap4(부트스크랩4)의 data-* 속성이 Bootstrap5(부트스크랩5)에서는 data-bs-* 속성으로 변경되었습니다.

// Bootstrap4
data-toggle="collapse" data-target="#navbarContent"

// Bootstrap5
data-bs-toggle="collapse" data-bs-target="#navbarContent"

Bootstrap4(부트스크랩 4)으로 된 소스를 복사하여 사용하시려면 data-* 속성을 data-bs-* 속성으로 변경하시기 바랍니다.

<button> 태그의 data-bs-target와 연결하기 위해 내비게이션 바를 가지고 있는 <div> 태그를 수정해야 합니다.

내비게이션 바를 가지고 있는 기존 <div> 태그입니다.

<div style="flex-basis:100%;">
</div>

<button> 태그의 data-bs-target와 연결하기 위해 기존 <div> 태그에 id를 설정합니다. 그리고 class에 .collapse와 .navbar-collapse를 추가합니다.

<div class="collapse navbar-collapse" id="navbarContent">
</div>

 

 

 

WAI-ARIA(Accessible Rich Internet Applications - 접근 가능한 리치 인터넷 애플리케이션)

ARIA는 HTML에 의미 체계를 추가하여 기능을 보완하고 확장시킵니다. 즉, ARIA는 기존에 의미가 없는 태그에 의미를 부여하여 웹 브라우저에서 해석될 수 있도록 aria-* 속성으로 추가합니다.

자세한 내용은 W3 사이트(https://www.w3.org/TR/html-aria/)에서 확인하세요.

Collapse(콜랩스)에서 사용되는 aria-* 속성들은 다음과 같습니다.

aria-controls은 컨트롤되는 콘텐츠입니다.

aria-expanded은 콘텐츠가 노출(펼쳐짐) 상태이면 true, 비노출(접혀짐) 상태이면 false입니다.

aria-label은 콘텐츠에 대한 라벨입니다.

<button> 태그에 aria-* 속성을 추가합니다.

<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarContent" aria-controls="navbarContent" aria-expanded="false" aria-label="Toggle navigation">
	<span class="navbar-toggler-icon"></span>
</button>

 

전체 소스입니다.

<header>
	<nav class="navbar navbar-expand-sm navbar-light bg-light">
		<div class="container-fluid">
			<router-link to="/" class="navbar-brand">
				<img alt="Vue logo" src="./assets/logo.png" style="height:25px;" />
			</router-link>
			<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarContent" aria-controls="navbarContent" aria-expanded="false" aria-label="Toggle navigation">
				<span class="navbar-toggler-icon"></span>
			</button>
			<div class="collapse navbar-collapse" id="navbarContent">
				<ul class="navbar-nav me-auto">
					<li class="nav-item">
						<router-link to="/" class="nav-link">Home</router-link>
					</li>
					<li class="nav-item">
						<router-link to="/about" class="nav-link">About</router-link>
					</li>
					<li class="nav-item">
						<router-link :to="{name: 'BoardList'}" class="nav-link">Board</router-link>
					</li>
					<li class="nav-item">
						<router-link :to="{name: 'Score'}" class="nav-link">Score</router-link>
					</li>
				</ul>
			</div>
		</div>
	</nav>
</header>

 

2. 콘솔을 실행하고 Vue 프로젝트가 있는 C:\workspaces\nodeserver\testvue 폴더로 이동합니다. 그리고 콘솔에서 npm run 명령어를 실행합니다.

npm run serve

 

3. 웹 브라우저에서 "http://localhost:8080"를 입력합니다. 그리고 내비게이션 바가 모바일 사이즈에서 정상적으로 동작하는 것을 확인하기 위해 웹 브라우저에서 F12 키를 누릅니다.

 

오른쪽 상단에 Toggle(토글) 버튼(3개의 선으로 되어 있어 이미지, 햄버거 버튼)이 노출됩니다.

 

반응형

 

Toggle(토글) 버튼을 클릭하면 내비게이션 바를 가지고 있는 <div> 태그가 애니메이션 처리로 노출(펼쳐짐) 되는 것을 확인할 수 있습니다.

다시 Toggle(토글) 버튼을 클릭하면 내비게이션 바를 가지고 있는 <div> 태그가 비노출(접혀짐) 됩니다.

 

 

Collapse(콜랩스) Class 변경

Toggle(토글) 버튼을 클릭하면 내비게이션 바를 가지고 있는 <div> 태그의 class가 다음처럼 변경됩니다.

노출(펼쳐짐)되면 .collapse -> .collapsing -> .collapse .show 으로 변경됩니다.

비노출(접혀짐)되면 .collapse .show -> .collapsing -> .collapse 으로 변경됩니다.

.collapse 콘텐츠를 숨깁니다.

.collapsing 전환 중에 적용됩니다.

.collapse .show 콘텐츠를 표시합니다.

Collapse(콜랩스) Event 흐름

콘텐츠가 노출(펼쳐짐)전에 event 호출 : show.bs.collapse

콘텐츠가 노출(펼쳐짐)된 후에 event 호출 : shown.bs.collapse

콘텐츠가 비노출(접혀짐)전에 event 호출 : hide.bs.collapse

콘텐츠가 비노출(접혀짐)된 후에 event 호출 : hidden.bs.collapse

event 처리에 대해서는 향후에 알아보겠습니다.

기존에 있는 <router-link> 링크와 <style>에 있는 #nav css는 삭제합니다.

<div id="nav">
	<router-link to="/">Home</router-link> |
	<router-link to="/about">About</router-link> |
	<router-link :to="{name: 'BoardList'}">Board</router-link> |
	<router-link :to="{name: 'Score'}">Score</router-link>
</div>

#nav {
  padding: 30px;
}

#nav a {
  font-weight: bold;
  color: #2c3e50;
}

#nav a.router-link-exact-active {
  color: #42b983;
}

 

 

전체 소스입니다.

<template>
	<header>
		<nav class="navbar navbar-expand-sm navbar-light bg-light">
			<div class="container-fluid">
				<router-link to="/" class="navbar-brand">
					<img alt="Vue logo" src="./assets/logo.png" style="height:25px;" />
				</router-link>
				<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarContent" aria-controls="navbarContent" aria-expanded="false" aria-label="Toggle navigation">
					<span class="navbar-toggler-icon"></span>
				</button>
				<div class="collapse navbar-collapse" id="navbarContent">
					<ul class="navbar-nav me-auto">
						<li class="nav-item">
							<router-link to="/" class="nav-link">Home</router-link>
						</li>
						<li class="nav-item">
							<router-link to="/about" class="nav-link">About</router-link>
						</li>
						<li class="nav-item">
							<router-link :to="{name: 'BoardList'}" class="nav-link">Board</router-link>
						</li>
						<li class="nav-item">
							<router-link :to="{name: 'Score'}" class="nav-link">Score</router-link>
						</li>
					</ul>
				</div>
			</div>
		</nav>
	</header>
	<main>
		<div class="header">
			<div class="topline">
				<div class="headmenu">
					<div v-if="isLogin">
						{{this.$store.state.loginStore.memberId}}님, 안녕하세요.
						<span @click="Logout()">로그아웃</span>
					</div>
					<div v-else>
						<router-link :to="{ name: 'Login', query: { returnUrl: '/' }}" v-show="isLogin == false">로그인</router-link>
					</div>
				</div>
			</div>
		</div>
		<router-view/>
	</main>
	<footer>
	</footer>
</template>

<script>
export default {
	name : 'App',
	methods : {
		Logout() {
			this.$store.dispatch("loginStore/doLogout");
			this.$router.push('/');
		}
	},
	computed : {
		isLogin() {
			return this.$store.getters['loginStore/isLogin'];
		}
	}
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

nav.navbar-transparent {
  position: absolute;
  top: 0;
  width: 100%;
  z-index: 100;
}

nav .navbar-nav a.nav-link {
  font-weight: bold;
  color: #2c3e50 !important;
  text-align:initial;
}

nav .navbar-nav a.router-link-exact-active {
  color: #42b983 !important;
}

.header { position:relative; }
.header .topline { position:relative; height:30px; margin:0 10px; }
.header .topline .headmenu { position:absolute; right:0; top:4px; }
.header .topline .headmenu a { font-weight:bold; color:#2c3e50; }
.header .topline .headmenu span { font-weight:bold; color:#2c3e50; cursor:pointer; text-decoration:underline; }
</style>

728x90
반응형