Blog

[Spring][258] 무한스크롤(Infinity Scroll) 기능 구현

Category
Author
Tags
PinOnMain
1 more property
무한 스크롤 구현 모습
무한 스크롤의 필요성
더보기 기능을 구현하면서 기본 페이징보다 상당히 뛰어난 사용자 경험을 상승 시키는 효과를 만들 수 있었습니다. 여기서 더욱 사용자의 상호작용을 고려하여 무한 스크롤을 통해 더보기의 자동화를 진행하고자 했습니다. 따라서 무한 스크롤은 더보기 기능의 또 다른 확장판으로 생각 할 수 있습니다.
우선 더보기 기능으로 페이징 자체의 원활한 기능적 목적을 달성하는데에는 Slice 인터페이스의 역할이 큽니다. 이번 무한 스크롤을 구현하는데 있어서도 최적화 된 구현체로 활용됩니다.
무한 스크롤은 다음에 조회할 페이지가 있는지 내부적으로 체크한 다음, 클라이언트에게 다음 페이지 여부를 알려주는 방식으로 구현할 수 있습니다.
[구현 코드] JavaScript의 HTTP Ajax 요청 구현부의 변경
무한 스크롤은 더보기와 다르게 더보기 버튼이 없이 스크롤의 위치에 따라 다음 페이지의 데이터 요청을 보내는 방식입니다. 따라서 더보기의 Ajax 요청 부분에서 버튼의 온클릭 이벤트가 아닌 스크롤과 관련된 이벤트가 추가되어야 합니다.
온클릭 버튼 이벤트와 마찬가지로 스크롤의 동작 조건에 해당되면, DispatcherServlet 을 거쳐 /search/loadMore 라는 API 엔드포인트로 다음 페이지의 데이터를 요청합니다.
저희 프로젝트의 레이아웃상 모든 페이지에서 스크롤이 나타나지 않으며, index-contents라는 태그 클래스에서만 스크롤이 나타납니다. 해당 selector를 통해 스크롤 감지 기능을 넣어두었습니다.
나머지 요청 및 응답 로직은 더보기와 같습니다.
$(document).ready(function() { let currentPage = 0; let loading = false; // 스크롤 이벤트 감지를 .index-contents에 적용 $('.index-contents').scroll(function() { // 스크롤이 특정 위치에 도달하면 추가 데이터 로드 if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight - 100 && !loading) { loading = true; // 서버에 다음 페이지 데이터 요청 $.ajax({ type: 'GET', url: '/search/loadMore', data: { bookCategoryName: $('#bookCategoryId').val(), keyword: $('#keyword').val(), page: currentPage + 1 }, dataType: 'json', success: function(data) { console.log(data); // books 배열에 접근하도록 수정 data[0].bookResponseDtos.forEach(book => { let bookHtml = `<tr> <td><input class="form-control" type="text" value="${book.bookName}" name="userId" readonly/></td> <td><input class="form-control" type="text" value="${book.bookAuthor}" name="username" readonly/></td> <td><input class="form-control" type="text" value="${book.bookPublish}" name="role" readonly/></td> <td><input class="form-control" type="text" value="${book.bookStatus}" name="role" readonly/></td> <td> <button type="button" class="btn btn-success rent-button" data-book-id="${book.bookId}">대출하기</button> <button type="button" class="btn btn-primary reserve-button" data-book-id="${book.bookId}">예약하기</button> </td> </tr>`; // 동적으로 생성된 HTML을 현재 테이블에 추가 $('#load-more-test').append(bookHtml); }); // 현재 페이지 업데이트 currentPage++; loading = false; // 로딩 상태 해제 }, error: function(xhr, status, error) { // 오류 처리 로직 console.error(error); loading = false; // 로딩 상태 해제 } }); } }); });
JavaScript
복사
eb10cd3df0933c53cdc5650db2094b8055a11eae
commit