안녕하세요 KB IT's Your Life 기자단 박민지입니다 !
이번주는 프로젝트의 막바지를 달려가고 있습니다 🏍🏍
오늘은 저희의 프로젝트 중 한 파트인 청년 부동산 도우미 구현 과정에 대해 다루어보려고 합니다 !
쉬운 말 사전
쉬운 말 사전은, 청년들이 어려워할 수 있는 부동산 용어들을 정리해놓은 파트입니다 !
기본적이고 가장 많이 사용되는 용어들 위주로 토글 형식을 통해 구현하였습니다.

위처럼 토글 형식으로 궁금했던 단어의 상세 내용들을 확인할 수 있습니다 !
부동산 사전에서 검색기능과 페이지네이션 코드를 나누어 구현과정을 적어보겠습니다.
✔Pagination (페이지네이션)
Pagination(페이지네이션) 컴포넌트를 나누어 여러 페이지로 구성된 데이터를 깔끔하게 표시해주어, 이전/다음 버튼을 통해 손쉽게 페이지 이동을 할 수 있도록 하였습니다 ! (기초 중에 기초인 기능이죠 ㅎㅎ 💨💨)
단계별로 구현해보겠습니다 !
1. Props 설정
const props = defineProps({
currentPage: {
type: Number,
required: true,
default: 1,
},
totalPages: {
type: Number,
required: true,
}
});
Pagination 컴포넌트는 현재 페이지와 총 페이지 수를 부모 컴포넌트로부터 전달받습니다. 이를 위해 defineProps를 사용해 currentPage와 totalPages를 설정했습니다 !
2. 버튼 비활성화 상태 관리

const isFirstPage = computed(() => props.currentPage === 1);
const isLastPage = computed(() => props.currentPage === props.totalPages);
이전 페이지와 다음 페이지는 조건에 따라 비활성화 설정을 해줘야합니다 !
예를 들어, 첫페이지에서는 이전 버튼이 비활성화되고, 마지막 페이지에서는 이후 버튼이 비활성화 되야합니다.
이를 위해 isFirstPage와 isLastPage를 computed 속성으로 설정했습니다.
3. 페이지 변경 이벤트 처리
const emit = defineEmits(['update:page']);
const changePage = (page) => {
if (page >= 1 && page <= props.totalPages) {
emit('update:page', page);
}
};
Pagination 컴포넌트는 사용자가 특정 페이지를 클릭했을 때 부모 컴포넌트로 페이지 번호를 전달해 줍니다. 이때 emit을 사용해 부모 컴포넌트에게 'update' 이벤트를 보냅니다.
4. 템플릿 구성
<template>
<nav aria-label="Page navigation example">
<ul class="pagination">
<li :class="['page-item', { disabled: isFirstPage }]">
<a href="#" class="page-link" aria-label="Previous" @click.prevent="changePage(currentPage - 1)">
<i class="fas fa-angle-left"></i>
</a>
</li>
<li class="page-item d-sm-none">
<span class="page-link page-link-static">{{ currentPage }} / {{ totalPages }}</span>
</li>
<li v-for="page in totalPages" :key="page" :class="['page-item', { active: page === currentPage }, 'd-none d-sm-block']">
<a href="#" class="page-link" @click.prevent="changePage(page)">
{{ page }}
</a>
</li>
<li :class="['page-item', { disabled: isLastPage }]">
<a href="#" class="page-link" aria-label="Next" @click.prevent="changePage(currentPage + 1)">
<i class="fas fa-angle-right"></i>
</a>
</li>
</ul>
</nav>
</template>
Pagination 컴포넌트의 UI는 간단한 HTML 구조와 Bootstrap 클래스를 사용하여 구현했습니다. 데스크탑에서는 모든 페이지 번호를 표시하고, 모바일에서는 현재 페이지만 표시되도록 반응형으로 처리했습니다 !
✔️ 아코디언 토글 기능 구현

마치 아코디언 악기와 같아 `아코디언 기능`이라는 이름이 붙여진 기능입니다.
주로 FAQ (자주 묻는 질문들 ) 형태의 페이지에 유용하게 사용됩니다.
항목을 클릭할 때마다 관련 내용이 펼쳐졌다가 다시 접히게 됩니다 !
1. 기본적인 HTML 구조 작성과 Style
<div v-for="(item, index) in filteredData" :key="index" class="accordion-item">
<button @click="toggleAccordion(index)" class="accordion-title">
{{ item.question }}
<span v-if="activeAccordion === index">▲</span>
<span v-else>▼</span>
</button>
<div v-if="activeAccordion === index" class="accordion-content">
<p>{{ item.answer }}</p>
</div>
</div>
<style scoped>
.accordion-title {
font-weight: 600;
font-size: 1.1rem;
cursor: pointer;
}
.accordion-content {
padding: 10px;
border-top: 1px solid #ddd;
transition: all 0.3s ease;
}
<style />
여기에서 @click 이벤트를 통해 toggleAccordion 메서드를 호출하여 클릭된 항목의 인덱스를 인자로 전달합니다.
activeAccordion이 현재 열려 있는 항목 인덱스를 저장하고, 이를 기준으로 콘텐츠를 보여주거나 숨겨줍니다.
2. toggleAccordion 메서드 구현
const activeAccordion = ref(null);
const toggleAccordion = (index) => {
activeAccordion.value = activeAccordion.value === index ? null : index;
};
toggleAccordion 메서드는 클릭된 인덱스와 현재 열린 인덱스를 비교하여 같은 경우에는 닫고, 다른 경우에는 새로 펼치도록 합니다.
이렇게 구현하면, 이미 열려 있는 항목을 클릭했을 때 activeAccordion 값을 null로 설정해 해당 항목이 닫히고, 다른 항목을 클릭했을 때는 activeAccordion 값이 해당 인덱스로 바뀌면서 새로 열린 항목만 표시됩니다.
✔️ 쉬운말 사전 검색 기능

사전에 필요한 검색 기능을 추가해보았습니다 -!
1. 기본적인 HTML 구조 작성과 Style 코드 작성
<template>
<div class="accordion-section">
<div class="d-flex justify-content-end">
<input v-model="searchQuery" type="text" placeholder="검색어를 입력하세요" class="search-input" />
</div>
<div v-for="(item, index) in paginatedData" :key="index" class="accordion-item">
<button @click="toggleAccordion(index)" class="accordion-title">
{{ item.question }}
<span v-if="activeAccordion === index">▲</span>
<span v-else>▼</span>
</button>
<div v-if="activeAccordion === index" class="accordion-content">
<p>{{ item.answer }}</p>
</div>
</div>
</div>
<template />
<style scoped>
.search-input {
margin-bottom: 10px;
padding: 8px 10px 8px 40px;
width: 40%;
border: 0px solid #ccc;
border-radius: 4px;
background-color: #F5F6F7;
background-image: url('https://cdn1.iconfinder.com/data/icons/hawcons/32/698627-icon-111-search-256.png');
background-size: 20px;
background-position: 10px center;
background-repeat: no-repeat;
}
<style />
2. Vue.js에서 data와 computed 사용하기
const searchQuery = ref(''); // 검색어 상태
const filteredData = computed(() => {
return dictionaryData.value.filter((item) =>
item.question.toLowerCase().includes(searchQuery.value.toLowerCase())
);
});
검색어가 입력되면 searchQuery에 저장되도록 v-model을 사용했습니다. 이 데이터를 바탕으로 computed 속성을 통해 필터링된 용어 데이터를 만들어보겠습니다.
3. 필터링된 데이터를 페이지에 출력하기
<div v-for="(item, index) in filteredData" :key="index" class="accordion-item">
<button @click="toggleAccordion(index)" class="accordion-title">
{{ item.question }}
<span v-if="activeAccordion === index">▲</span>
<span v-else>▼</span>
</button>
<div v-if="activeAccordion === index" class="accordion-content">
<p>{{ item.answer }}</p>
</div>
</div>
filteredData는 검색어에 따라 실시간으로 필터링된 데이터를 반환합니다. 이제 이 데이터를 HTML 내에서 반복문을 사용해 출력합니다 :)

이상 간단한 사전과 검색기능에 대해 다루어보았습니다 :)
이제, 발표를 앞두고 떨리는 마음을 가지고 있는데요. 발표가 끝난 후 주요 기능들을 조금 더 소개드리고 싶어요 ㅎㅎ !
다음 주에 다시 돌아오겠습니다 감사합니다 .
'[KB IT's Your Life] Today I Learnd' 카테고리의 다른 글
| [KB IT's Your Life] 최종 프로젝트 회고 (Feat: 최우수상 선발) 💡 (2) | 2024.10.23 |
|---|---|
| [KB IT's Your Life] 종합실무프로젝트2 💡 (4) | 2024.09.30 |
| [KB IT's Your Life] 8주차 종합실무프로젝트💡 (8) | 2024.09.18 |
| [KB IT's Your Life] 7주차 컴포넌트 백엔드: Spring Security💡 (4) | 2024.09.11 |
| [KB IT's Your Life] 6주차 컴포넌트 백엔드: 게시판 만들기💡 (3) | 2024.09.02 |