Vue.js 3 & NodeJS/Vue 3

Vue CLI 부트스크랩 5 카드 - Vue CLI Bootstrap 5, Card, Grid Row Columns, justify-content-betweend

carrotweb 2022. 3. 27. 22:52
728x90
반응형

메인 페이지의 본문 영역을 Bootstrap의 Card(카드)를 사용하여 콘텐츠(게시물)가 나타나게 구성하겠습니다.

먼저 Bootstrap의 Grid System(그리드 시스템)을 사용하여 Row columns(행(row)에 대한 열(col))을 설정합니다.

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

<template> 태그에서 메인 페이지 상단 영역 다음에 콘텐츠를 표시하기 위한 영역으로 <div> 태그를 추가합니다. Bootstrap의 Grid System(그리드 시스템)을 사용하여 반응형으로 웹 브라우저의 가로 화면의 크기에 따라 행(row)에 몇 개의 콘텐츠가 나타나게 할지 설정합니다.

<div class="py-5">
	<div class="container">
		<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3">
			<div class="col" style="padding:100px 100px; border:solid 1px black; background-color:white;">
				col1
			</div>
			<div class="col" style="padding:100px 100px; border:solid 1px black; background-color:white;">
				col2
			</div>
			<div class="col" style="padding:100px 100px; border:solid 1px black; background-color:white;">
				col3
			</div>
		</div>
	</div>
</div>

화면에 영역을 보이기 위해서는 <div>에 style 속성과 텍스트를 추가했습니다. 테스트를 위해 추가한 것으로 테스트 후 삭제하시기 바랍니다.

row-cols-md-3은 가로 화면 크기가 768px보다 크거나 같으면 행(row)에 열(col)이 3개씩 배치됩니다.

row-cols-sm-2는 가로 화면 크기가 576px보다 크거나 같으면 행(row)에 열(col)이 2개씩 배치됩니다.

row-cols-1은 행(row)에 열(col)이 1개씩 배치됩니다.

웹 브라우저의 가로 화면 크기가 768px 이상일 때는 한 행(row)에 열(col)이 3개씩 배치됩니다.

 

웹 브라우저의 가로 화면 크기가 576px 이상일 때는 한 행(row)에 열(col)이 2개씩 배치됩니다.

 

모바일 사이즈(웹 브라우저의 가로 화면 크기가 576px 이하이면)에서는 한 행(row)에 열(col)이 1개만 배치됩니다.

 

 

Bootstrap - Card

Bootstrap의 Card(카드)는 기본적으로 카드 보디(card-body)에 카드 타이틀(card-title)과 카드 텍스트(card-text)로 구성됩니다. 그리고 이미지를 카드 보디의 상단이나 하단 또는 사이드에 배치시킬 수 있습니다.

그리고 카드 헤더(card-header)나 카드 푸터(card-footer)를 포함해서 구성할 수 있습니다.

<div class="card">
	<div class="card-body">
		<h5 class="card-title">Card Title</h5>
		<p class="card-text">Card Content</p>
	</div>
</div>

<div class="card">
	<img class="card-img-top" src="..." alt="...">
	<div class="card-body">
		<h5 class="card-title">Card Title</h5>
		<p class="card-text">Card Content</p>
		<a href="#" class="btn btn-primary">Link</a>
	</div>
</div>

<div class="card">
	<div class="card-header">Card Header</div>
	<img class="card-img-top" src="..." alt="...">
	<div class="card-body">
		<h5 class="card-title">Card Title</h5>
		<p class="card-text">Card Content</p>
	</div>
	<div class="card-footer">Card Footer</div>
</div>

 

현재 Node.js 레스트 API 서버에는 이미지가 업로드 기능이 없고 제목과 내용만 있는 간단한 레스트 API 서버입니다.

그래서 Bootstrap Card(카드)로 카드 타이틀(card-title)과 카드 서브타이틀(card-subtitle), 링크, 날짜로 구성하겠습니다.

2. C:\workspaces\nodeserver\testvue\src\views\BoardList.vue 파일을 오픈하여 <script>에서 data와 methods에 있는 getBoardList() 메서드를 복사하여 Home.vue 파일의 <script>에 추가합니다.

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue';
import * as bootstrap from 'bootstrap';

export default {
	name: 'Home',
	components: {
		HelloWorld
	},
	data : function() {
		return {
			boardList : []
		};
	},
	methods : {
		mainTopCarouselPrevClick() {
			var mainTopCarousel = document.querySelector('#mainTopCarousel');
			var carousel = bootstrap.Carousel.getInstance(mainTopCarousel);
			carousel.prev();
		},
		mainTopCarouselNextClick() {
			var mainTopCarousel = document.querySelector('#mainTopCarousel');
			var carousel = bootstrap.Carousel.getInstance(mainTopCarousel);
			carousel.next();
		},
		mainTopCarouselPlayPauseClick(event) {
			var mainTopCarousel = document.querySelector('#mainTopCarousel');
			var carousel = bootstrap.Carousel.getInstance(mainTopCarousel);
			if (mainTopCarousel.classList.contains("pause")) {
				mainTopCarousel.classList.remove("pause");
				event.target.classList.remove("bi-play-fill");
				event.target.classList.add("bi-pause-fill");
				carousel.cycle();
			} else {
				mainTopCarousel.classList.add("pause");
				event.target.classList.remove("bi-pause-fill");
				event.target.classList.add("bi-play-fill");
				carousel.pause();
			}
		},
		getBoardList() {
			this.axios.get("http://localhost:9000/boards").then((res)=>{
				console.log(res);
				this.boardList = res.data.data;
			}).catch((err) => {
				console.log(err);
			});
		}
	},
	mounted() {
		this.getBoardList();
	}
};
</script>

향후 Node.js 레스트 API 서버에 기능을 추가하여 변경하도록 하겠습니다.

 

<template>에서 추가한 콘텐츠 영역 부분을 <script>의 data에 선언된 배열 객체(boardList)를 이용하여 열(col)를 생성하게 변경합니다.

<div class="py-5">
	<div class="container text-start">
		<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3">
			<div class="col" v-for="boardItem in boardList" v-bind:key="boardItem.no">
				<div class="card">
					<div class="card-body">
						<h5 class="card-title">{{boardItem.subject}}</h5>
						<h6 class="card-subtitle mb-2 text-muted">{{boardItem.writer}}</h6>
					</div>
				</div>
			</div>
		</div>
	</div>
</div>

현재 배열 객체(boardList)에는 콘텐츠 내용이 없기 때문에 카드 텍스트(card-text)는 사용하지 않았습니다.

그리고 카드 서브타이틀(card-subtitle)을 사용하여 작성자 아이디가 표시되도록 하였습니다.

 

 

3. 카드 보디(card-body)에 보기 버튼과 작성일자를 추가합니다.

<div class="py-5">
	<div class="container text-start">
		<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3">
			<div class="col" v-for="boardItem in boardList" v-bind:key="boardItem.no">
				<div class="card">
					<div class="card-body">
						<h5 class="card-title">{{boardItem.subject}}</h5>
						<h6 class="card-subtitle mb-2 text-muted">{{boardItem.writer}}</h6>
						<div class="d-flex justify-content-between align-items-center">
							<div class="btn-group">
								<button type="button" class="btn btn-sm btn-outline-secondary" @click="boardNoClick(boardItem)">보기</button>
							</div>
							<small class="text-muted">{{boardItem.writedate}}</small>
						</div>
					</div>
				</div>
			</div>
		</div>
	</div>
</div>

.justify-content-betweend으로 버튼과 작성일자는 양쪽으로 정렬됩니다. (.justify-content-betweend은 justify-content: space-between 과 동일합니다.)

 

버튼을 .btn-group 안으로 추가한 이유는 수정 버튼을 추후에 추가하기 위해서입니다.

BoardList.vue 파일의 <script>에서 methods에 boardNoClick() 메서드를 Home.vue 파일의 <script>에 추가합니다.

boardNoClick(boardItem) {
	this.$router.push({name : 'BoardView', query : {boardNo : boardItem.no}});
}

보기 버튼을 클릭하면 기존의 게시판의 뷰 페이지로 이동합니다.

모바일 사이즈에서는 다음과 같이 나타납니다.

728x90
반응형