무한 스크롤이란 페이스북의 타임 라인처럼 스크롤이 어느 위치에 도달하면 다음 데이터를 가져오는 기법을 의미합니다.

그러기 위해서는 Ajax 통신이 필요하며, 언제 비동기 요청을 보낼 것인지에 대한 알고리즘이 필요합니다.



1. 알고리즘



  • document height
    • 문서 전체의 높이를 의미합니다.
  • window height
    • 화면의 높이를 의미합니다.
  • scroll top
    • 스크롤의 top이 위치하고 있는 높이를 의미합니다.
  • 각각의 값은 모두 JS의 window 객체를 통해 구할 수 있습니다.
  • 코드로서 살펴보겠지만, window height + scroll top의 값과 특정 높이의 값을 더해서 document height 값 보다 클 경우, 데이터를 가져오도록 할 것입니다.




2. 구현

<!DOCTYPE html>
<html>
<head>
<title>mysite</title>

<meta http-equiv="content-type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="${pageContext.request.contextPath }/assets/css/guestbook-ajax.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">

<script type="text/javascript" src="${pageContext.request.contextPath }/assets/js/jquery/jquery-1.9.0.js"></script>
</head>

<body>
<div>
<ul id="list-guestbook">
</ul>

</div>
</body>


<script type="text/javascript">
let isEnd = false;

$(function(){
$(window).scroll(function(){
let $window = $(this);
let scrollTop = $window.scrollTop();
let windowHeight = $window.height();
let documentHeight = $(document).height();

console.log("documentHeight:" + documentHeight + " | scrollTop:" + scrollTop + " | windowHeight: " + windowHeight );

// scrollbar의 thumb가 바닥 전 30px까지 도달 하면 리스트를 가져온다.
if( scrollTop + windowHeight + 30 > documentHeight ){
fetchList();
}
})
fetchList();
})

let fetchList = function(){
if(isEnd == true){
return;
}

// 방명록 리스트를 가져올 때 시작 번호
// renderList 함수에서 html 코드를 보면 <li> 태그에 data-no 속성이 있는 것을 알 수 있다.
// ajax에서는 data- 속성의 값을 가져오기 위해 data() 함수를 제공.
let startNo = $("#list-guestbook li").last().data("no") || 0;
$.ajax({
url:"/guestbook/api/guestbook/list?no=" + startNo ,
type: "GET",
dataType: "json",
success: function(result){
// 컨트롤러에서 가져온 방명록 리스트는 result.data에 담겨오도록 했다.
// 남은 데이터가 5개 이하일 경우 무한 스크롤 종료
let length = result.data.length;
if( length < 5 ){
isEnd = true;
}
$.each(result.data, function(index, vo){
renderList(false, vo);
})
}
});
}

let renderList = function(mode, vo){
// 리스트 html을 정의
let html = "<li data-no='"+ vo.no +"'>" +
"<strong>"+ vo.name +"</strong>" +
"<p>"+ vo.content.replace(/\n/gi, "<br>") +"</p>" +
"<strong></strong>" +
"<a href='#' data-no='"+ vo.no +"'>삭제</a>" +
"</li>"

if( mode ){
$("#list-guestbook").prepend(html);
}
else{
$("#list-guestbook").append(html);
}
}
</script>
</html>


js 각 함수의 코드 설명은 다음과 같습니다.

  • 즉시실행 함수
    • 스크롤 이벤트가 발생하면 console에 document height , window의 height , scroll top 값을 확인하기 위해 출력합니다.
    • 그리고 scroll bar의 밑바닥 높이가 30px이 되면 fetchList() 함수를 호출하여 데이터를 가져오도록 합니다.


  • fetchList()
    • fetchList() 함수는 Ajax 요청을 통해 서버로부터 비동기 방식을 데이터를 리스트로 가져옵니다.
    • 만약 데이터가 5개 이하면 더 이상 무한 스크롤을 진행하지 않도록 하기 위해 전역 변수인 isEnd = true로 할당합니다.
    • 그리고 데이터의 개수 만큼 반복문을 돌면서 renderList() 함수를 호출합니다.
  • renderList()
    • renderList() 함수는 출력할 데이터를 HTML 태그와 함께 작성한 후, prepend(), append() 메서드를 호출합니다.
    • mode는 prepend() , append()를 선택할 수 있도록 지원하기 위해 사용됩니다.



이상으로 jQuery로 무한 스크롤을 적용해보았습니다.

충분한 데이터가 없다면 적용이 잘 안될 수도 있기 때문에, 테스트를 하시려면 많은 데이터가 필요합니다.