Vue.js 3 & NodeJS/Vue 3

Vue CLI SNS처럼 주제별 베스트 탑 표시(부트스크랩 5 카드) - Vue CLI SNS Theme Best Top(Bootstrap 5, Card UI)

carrotweb 2022. 6. 12. 19:39
728x90
반응형

이전에 Node.js 레스트 API에 카테고리, 베스트 탑을 추가하였습니다. 이번에는 Node.js 레스트 API 서버로부터 주제별 베스트 탑을 가져와 부트스크랩 카드 UI를 사용하여 리스트 위에 추가하겠습니다.

 

 

주제별 베스트 탑 가져오기

 

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

주제별 베스트 탑 리스트를 저장하기 위해 data에 주제별 베스트 탑 리스트(bestTopList)를 추가합니다.

data : function() {
	return {
		boardList : [],
		boardPagination : {},
		categoryList : [],
		category : 0,
		bestTopList : [] 
	};
}

 

2. <script>의 getBestTopList() 메서드를 추가하여 Node.js 레스트 API 서버로부터 주제별 베스트 탑 리스트를 가져오게 합니다.

getBestTopList() {
	this.axios.get("http://localhost:9000/boards/bestcategoryliketop").then((res)=>{
		this.bestTopList = res.data.data;
	}).catch((err) => {
		console.log(err);
	});
}

 

그리고 <script>의 mounted() 메서드에 getBestTopList() 메서드를 getCategoryList() 메서드 위에 추가합니다.

mounted() {
	this.getBestTopList();
	this.getCategoryList();
	this.getBoardList(1);
}

 

3. Category(카테고리) UI 위에 Card(카드) UI로 주제별 베스트 탑을 추가합니다.

이전 Vue CLI 부트스크랩 5 카드(https://carrotweb.tistory.com/174), Vue CLI 부트스크랩 5 카드 말줄임(...)(https://carrotweb.tistory.com/200)를 참고하시기 바랍니다.

 

카드 구조와 내용을 그래도 복사하고 boardList 대신 bestTopList으로 변경합니다.

그리고 카테고리가 4개로 구성되어 있으므로 row-cols-md-3을 row-cols-md-4(가로 화면 크기가 768px보다 크거나 같으면 행(row)에 열(col)이 4개씩 배치)로 변경합니다.

<div class="pt-5">
	<div class="container text-start">
		<div class="row row-cols-1 row-cols-sm-2 row-cols-md-4">
			<div class="col my-2" v-for="boardItem in bestTopList" v-bind:key="boardItem.no">
				<div class="card">
					<img class="card-img-top" :src="(boardItem.poster.toUpperCase().startsWith('HTTP') ? '' : 'http://localhost:9000') + boardItem.poster" alt="">
					<div class="card-body">
						<h5 class="card-title">{{boardItem.subject}}</h5>
						<h6 class="card-subtitle mb-2 text-muted">{{boardItem.writer}}</h6>
						<p class="card-text">{{boardItem.content}}</p>
						<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>

 

리스트 UI처럼 사용자 프로필 추가 닉네임, 작성날짜(SNS처럼 지난 시간 표시)로 변경, 보기 버튼 삭제하고 클릭 이벤트는 card에 추가 처리하겠습니다.

<div class="pt-5">
	<div class="container text-start">
		<div class="row row-cols-1 row-cols-sm-2 row-cols-md-4">
			<div class="col my-2" v-for="boardItem in bestTopList" v-bind:key="boardItem.no">
				<div class="card" @click="boardNoClick(boardItem)">
					<img class="card-img-top" :src="(boardItem.poster.toUpperCase().startsWith('HTTP') ? '' : 'http://localhost:9000') + boardItem.poster" alt="">
					<div class="card-body">
						<h5 class="card-title">{{boardItem.subject}}</h5>
						<div class="card-subtitle my-3 list-group-item-writer">
							<div class="list-group-item-writer-profile">
								<img :src="(boardItem.writerProfile.toUpperCase().startsWith('HTTP') ? '' : 'http://localhost:9000') + boardItem.writerProfile" alt="">
							</div>
							<span>{{boardItem.writerNickname}}</span>
							<small>{{elapsedText(boardItem.writedate)}}</small>
						</div>
						<p class="card-text">{{boardItem.content}}</p>
					</div>
				</div>
			</div>
		</div>
	</div>
</div>

 

 

카드에 라우터 링크 처리하면 카드 전체에 링크(A Tag)가 걸리게 되어 <style>에 css를 추가 처리해야 합니다. 그래서 클릭 이벤트로 처리하겠습니다.

<router-link :to="{name : 'BoardView', query : {boardNo : boardItem.no}}">
	<div class="card">
		<img class="card-img-top" :src="(boardItem.poster.toUpperCase().startsWith('HTTP') ? '' : 'http://localhost:9000') + boardItem.poster" alt="">
		<div class="card-body">
			<h5 class="card-title">{{boardItem.subject}}</h5>
			<div class="card-subtitle mt-3 mb-3 list-group-item-writer">
				<div class="list-group-item-writer-profile">
					<img :src="(boardItem.writerProfile.toUpperCase().startsWith('HTTP') ? '' : 'http://localhost:9000') + boardItem.writerProfile" alt="">
				</div>
				<span>{{boardItem.writerNickname}}</span>
				<small>{{elapsedText(boardItem.writedate)}}</small>
			</div>
			<p class="card-text">{{boardItem.content}}</p>
		</div>
	</div>
</router-link>

 

그리고 폰트와 색상도 리스트 UI와 동일하게 처리하겠습니다. 카드 CSS는 em 단위를 사용하고 있어서 카드에 폰트 크기만 설정하면 됩니다. 다만 card-title이 h5로 font-size가 1.25rem 입니다. 그래서 리스트 타이틀처럼 폰트 크기와 볼드를 추가해주면 됩니다.

.card {
  font-size: 14px;
}

.card-title {
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.4em;
  height: 2.8em;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  font-size: 16px;
  font-weight: 600; --> 추가
}

 

주제별 베스트 탑을 구분하기 위한 타이틀을 추가하고 <style>에 css를 추가합니다.

<div class="pt-5">
	<div class="container text-start">
		<div class="header">
			<span class="title">주제별 BEST TOP</span>
		</div>
		<div class="row row-cols-1 row-cols-sm-2 row-cols-md-4">
			<div class="col my-2" v-for="boardItem in bestTopList" v-bind:key="boardItem.no">
				<div class="card" @click="boardNoClick(boardItem)">
					<img class="card-img-top" :src="(boardItem.poster.toUpperCase().startsWith('HTTP') ? '' : 'http://localhost:9000') + boardItem.poster" alt="">
					<div class="card-body">
						<h5 class="card-title">{{boardItem.subject}}</h5>
						<div class="card-subtitle my-3 list-group-item-writer">
							<div class="list-group-item-writer-profile">
								<img :src="(boardItem.writerProfile.toUpperCase().startsWith('HTTP') ? '' : 'http://localhost:9000') + boardItem.writerProfile" alt="">
							</div>
							<span>{{boardItem.writerNickname}}</span>
							<small>{{elapsedText(boardItem.writedate)}}</small>
						</div>
						<p class="card-text">{{boardItem.content}}</p>
					</div>
				</div>
			</div>
		</div>
	</div>
</div>
.header {
  margin-bottom: 10px;
}

.header > .title {
  font-weight: bold;
  color: #000 !important;
  font-size: 18px;
}

 

이제 블로그 사이트처럼 UI가 구성을 갖추게 되었습니다.

728x90
반응형