반응형
목차
개발환경
백엔드 | 프론트엔드 |
Express.js(Node.js 기반 웹 프레임워크) | EJS 템플릿 엔진(Embedded JavaScript) |
라우트
router.get('/searchHistoryScroll', MyController.getHistoryIndexUsePaging);
라우트 파일에서 /searchHistoryScroll url을 MyController의 getHistoryIndexUsePaging 함수와 매핑
컨트롤러
// 상단 정의 부분
const axios = require('axios');
// 라우트에 정의된 함수
exports.getHistoryIndexUsePaging = async(req, res) => {
let pageNo = req.query.page[0]; // 조회할 페이지 번호
queryParams = {
page: pageNo,
size: 10, // 한번에 조회할 데이터 개수
};
const headers = {
'Content-Type': 'application/json',
//세션 아이디
'hiddenValue': req.session.MEMB.MEMB_ID
};
try {
// 데이터 조회 API 호출
const historyUrl = `${process.env.TEST_API}/history`;
// API 조회 결과
const historyList = await axios.get(historyUrl, {
headers: headers,
params: queryParams,
timeout: 20000
});
//데이터를 json형식으로 클라이언트에 반환
res.json({
data: {
historyList: historyList.data
}
});
} catch (error) {
console.error("error :: " + error);
res.status(500).json({ success: false, message: 'Failed to fetch data' });
}
}
서버에서는 클라이언트에서 전달된 페이지 번호와 데이터 사이즈를 API의 parameter의 인자로 넘기며
API를 통해 데이터를 받아와서 정상인 경우 json형식의 데이터를, 오류 발생 시 로그를 출력하고
상태코드 500과 실패 메시지를 반환한다.
EJS
<header class="sub-header nav-padding">
<nav class="loginfixed">
<dl>
<dd></dd>
</dl>
<dl>
<dd>내역</dd>
</dl>
<dl>
<!-- 화면 로드 시 전체 개수를 가지고 있음(이건 서버의 다른 함수에서 전달했다고 가정) -->
<input type="hidden" id="totalCountHidden" value="<%- data.totalCount %>">
</dl>
</nav>
</header>
<div class="list-box">
<div class="list-item-box">
<div class="list-item">
<div class="list-top">
<dl>
<!-- 화면 로드 시 전달했다고 가정 -->
<dd>총 <%- data.totalCount %>건</dd>
</dl>
</div>
<!-- 이 요소 밑에 동적으로 데이터를 추가 -->
<div class="list-bottom"></div>
</div>
</div>
</div>
<!-- API 호출하기 위해 axios 불러옴 -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
let isLoading = false; // 데이터 로드 여부
let page = 1; // 현재 페이지 번호
let lastScrollY = window.scrollY; // 마지막 스크롤 위치
$(document).ready(function () {
loadMorePosts(page);
});
// 스크롤 이벤트
window.addEventListener('scroll', function () {
if (window.scrollY > lastScrollY) { // 현재 스크롤 위치가 이전 스크롤 위치보다 큰 경우(아래를 향함)
// 화면의 최하단에 도달했는지 판단
if (window.innerHeight + window.scrollY >= document.documentElement.scrollHeight - 1) {
if (!isLoading) { // 데이터가 로드중이 아닐 때
isLoading = true;
page++;
loadMorePosts(page); // 추가 데이터를 불러오는 함수
}
}
}
lastScrollY = window.scrollY; // 스크롤 위치 업데이트
});
//데이터 조회 후 데이터가 있으면 DOM의 마지막 요소에 추가
async function loadMorePosts(pageNo) {
var totalCount = $("#totalCountHidden").val();
isLoading = false;
let htmlContent = '';
const queryParams = {
page: Array.isArray(pageNo) ? pageNo[0] : pageNo
};
const requestUrl = `/searchHistoryScroll?${new URLSearchParams(queryParams).toString()}`;
try {
const response = await axios.get(requestUrl, {
params: queryParams,
timeout: 20000,
});
const HistoryList = response.data;
if(totalCount < 1) {
htmlContent += `
<div class="no-list">
<ul>
<li>내역이 없어요!</li>
</ul>
</div>
`;
$('.list-bottom').append(htmlContent);
} else {
updateCreditHistory(historyList.data.historyList);
}
} catch (error) {
console.error('데이터를 불러오는 중 오류 발생:', error);
}
}
// 조회한 데이터를 DOM 요소의 마지막 자식으로 append
function updateCreditHistory(data) {
let container = $('.list-bottom');
let htmlContent = '';
for (let i = 0; i < data.data.length; i++) {
const item = data.data[i];
htmlContent += `
<dl>
<dd>${item.startDate.substring(0, 16).replace(/-/g, '.')}</dd>
<dd>${item.endDate.substring(0, 16).replace(/-/g, '.')}</dd>
</dl>
`;
}
$('.list-bottom').append(htmlContent);
}
</script>
전체 개수를 가져와서 데이터가 없으면 내역이 없다고 표시하고 데이터가 있으면
스크롤 이벤트 시 페이지 번호 증가시키며 서버를 호출 해 데이터가 있으면 .list-bottom요소의 마지막에
계속 append를 한다.(덮어쓰는게 아니다.)
기존의 웹 방식에서는 페이지를 누를 때 마다 한 페이지에 보여질 사이즈만큼 계속 새로 생성했는데 모바일에서는 스크롤 할 때마다 새로 가져온 데이터가 하단에 추가가 되어야 하고 다시 위로 스크롤 했을 때에도 기존 데이터도 유지 되어야 한다.
개인 스터디 기록을 메모하는 공간이라 틀린점이 있을 수 있습니다.
틀린 점 있을 경우 댓글 부탁드립니다.
반응형
'IT > development' 카테고리의 다른 글
[jQuery] 체크 이벤트 강제 발생 시키기 (2) | 2025.01.11 |
---|---|
[java] 직접 구현한 List 추상화 (feat. 의존관계 주입) (11) | 2025.01.05 |
[java] 직접 구현하는 연결리스트 > 추가, 삭제 기능 (feat. 자료구조) (9) | 2025.01.05 |
[java] LinkedList(연결 리스트) 내 방식대로 이해 (feat. 자료구조) (16) | 2025.01.04 |
[java] generic review (feat. 동영상 촬영) (27) | 2024.12.27 |
댓글