이전 글: Vue.js: 기초 사용 방법 + 예제: 이름으로 보는 운세
요구사항: Home, Portfolio, Guestbook 3개의 메뉴로 된 홈페이지를 만들되 각 메뉴는 Vue.js의 컴포넌트를 사용하여 작성하시오.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Homepage</title>
<link rel="stylesheet" href="[부트스트랩-cdn-주소]">
</head>
<body class=container>
<nav id="home-nav" class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="#">{{ title }}</a>
<button class="navbar-toggler" type="button">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarColor02">
<ul class="navbar-nav mr-auto">
<li class="nav-item" v-for="item in menus">
<a class="nav-link" href="#" v-on:click="moveMenu">{{ item }}</a>
</li>
</ul>
</div>
</nav>
<!-- 컴포넌트 부분, :contents 는 article객체의 currentContents에 있는 내용을 불러온다. -->
<article id="home-article" class="row">
<display-article :contents="currentContents">
</display-article>
</article>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="./index.js"></script>
</body>
</html>
<article>은 HTML5에 나오는 태그로 웹사이트에서 읽을 거리 등 주요 내용이 들어가는 의미를 가진(semantic) 구역(div) 태그입니다. 하위에 위치한 <display-article>이 컴포넌트가 들어갈 자리입니다. 이 태그의 이름은 실제 HTML5 스펙에는 없는 이름으로 Vue.js의 컴포넌트의 이름은 만드는 사람 마음대로 지을 수 있다는 것이 특징입니다.
컴포넌트는 HTML 상에서는 껍데기 부분만 선언해놓고 실제 내용은 다른 곳에서 작성된다는 특징이 있습니다. 보통 규모가 있는 개발 환경에서는 *.Vue 라는 확장자의 파일로 따로 작성되는데, 지금은 예제이므로 단순하게 컴포넌트를 스크립트 부분에 선언해 보겠습니다.
:contents는 v-bind:contents의 약자로 currentContents 의 내용이 (실시간으로) 컴포넌트의 props의contents에 대입된다는 의미입니다.
Vue.component('display-article', {
template: '<div class="col-12 text-primary">{{ contents }}</div>',
props: ['contents']
})
컴포넌트의 전역 선언 방법입니다. 지역 스코프로 선언하는 방법도 있지만 지금은 넘어가겠습니다. 프로퍼티(props)로 contents를 지정하고, 그 contents를 템플릿 안에서 사용한다는 의미입니다. prop의 contents가 바뀔 때마다 템플릿 안의 내용도 바뀌게 됩니다. 그럼 이 contents라는 이름의 무언가를 다루는 방법에 대해 알아보겠습니다.
그 전에 템플릿에 대한 주의 사항이 있습니다. 템플릿(template)는 실제 컴포넌트 안에 렌더링될 내용들이 들어 있는 곳인데, 템플릿의 내용은 <display-article>의 하위 태그로 들어가는 것이 아니며, 해당 태그를 대체합니다. 즉, 렌더링된 최종 결과에서 임의로 선언한 <display-article>는 사라지고 그 자리를 템플릿의 <div> 태그가 차지할 것입니다.
var nav = new Vue({
el: "#home-nav",
data: {
title: "홈페이지",
menus: ["Home", "Portfolio", "Guestbook"],
contents: {
home: "첫화면입니다",
portfolio: "포트폴리오입니다.",
guestbook: "방명록입니다."
}
},
methods: {
moveMenu: function (e) {
var menu = e.target.text.toLowerCase()
// 클릭하면 메뉴값을 article.currnetContents에 대입한다.
article.currentContents = this.contents[menu]
}
}
})
var article = new Vue({
el: "#home-article",
data:{
currentContents: ""
}
})
// 첫 화면 지정
window.onload = function(){
article.currentContents = nav.contents.home
}
nav 변수는 내비게이터 부분인 <nav> 태그를 관리하는 Vue.js 인스턴스입니다. methods에 moveMenu라는 것이 있는데 이 메소드가 실행되면 contents[menu]의 내용이 article.currentContents에 할당합니다. 예를 들어 menu가 guestbook이라면 this.contents["guestbook"] 에 있는 "방명록입니다." 라는 내용을 article.currentContents에 할당하겠다는 의미와 동일합니다.
맨 위 HTML 부분의 <display-article> 태그에서 :contents="currentContents" 부분을 다시 보겠습니다. <article>이 Vue.js 인스턴스 관리 하에 있으므로 하위에 있는 <display-article>이라는 태그도 currentContents 데이터를 인식할 수 있습니다. 여기서 contents는 전역 선언한 컴포넌트 'display-article' 의 프로퍼티입니다. currentContents가 nav 인스턴스의 메소드에 의해 변경되면, 그것이 컴포넌트의 프로퍼티인 contents로 전달되며, 프로퍼티는 다시 템플릿(template) 안으로 전달됩니다. 브라우저에서는 템플릿의 내용을 바탕으로 컴포넌트 안이 렌더링됩니다. 이것을 순서대로 표시하면 아래 그림과 같습니다.

결과화면입니다. JSFiddle에서도 볼 수 있습니다.





