반응형
스크립트
<script>
let indexpage = 1; // 현재 페이지 초기화
let isLoading = false; // 추가 로드 상태 확인 변수
window.onload = function(){
window.addEventListener('scroll', () => {
const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
// 스크롤이 바닥에 도달했을 때
if (scrollTop + clientHeight >= scrollHeight - 5 && !isLoading) {
isLoading = true; // 로딩 중 상태로 변경
loadMore();
}
});
}
//추가 데이터를 불러오는 함수
function loadMore() {
indexpage++; // 페이지 번호 증가
$.ajax({
url: `<%= request.getContextPath() %>/board/loadMore.do`,
method: 'GET',
data: { indexpage: indexpage },
success: function(data) {
let html = '';
data.forEach(item => {
html += `<div class='listDiv' id='\${item.bno}'>
<img style='width: 250px; height: 250px; border-radius: 20px;'
src='<%= request.getContextPath() %>/upload/\${item.pname}' alt='Image ${item.bno}'>
</div>`;
});
$('#indexDiv').append(html);
isLoading = false;
},
error: function() {
console.error("더 많은 게시물을 로드하는 중 오류가 발생했습니다.");
isLoading = false;
}
});
}
</script>
- indexpage = 1;은 현재 페이지를 나타내는 변수입니다. 초기값은 1로 설정되었습니다.
- isLoading = false;는 추가 데이터를 로드 중인지 확인하는 변수입니다. 로딩 중일 때는 true, 아닐 때는 false로 설정됩니다.
- 스크롤 이벤트 :
- window.addEventListener('scroll', () => {...}) 부분은 사용자가 스크롤을 내렸을 때 실행됩니다.
- scrollTop, scrollHeight, clientHeight는 각각 스크롤 위치, 전체 페이지 높이, 현재 화면 높이를 의미합니다.
- 스크롤이 거의 바닥에 도달했을 때(scrollTop + clientHeight >= scrollHeight - 5) 데이터를 추가로 로드하기 위해 loadMore() 함수를 호출합니다.
- loadMore() 함수 :
- indexpage++로 페이지 번호를 증가시킵니다.
- AJAX 요청을 보내 <%= request.getContextPath() %>/board/loadMore.do로부터 다음 페이지의 데이터를 가져옵니다.
- 성공적으로 데이터를 받아오면 data 배열을 반복하여 HTML 요소로 변환하고, #indexDiv에 추가합니다. 로드가 완료되면 isLoading을 false로 변경해 다음 로드 준비를 합니다.
1. window.addEventListener('scroll', () => {...})
- window 객체에 scroll 이벤트 리스너가 추가되었습니다. 즉, 사용자가 스크롤을 할 때마다 특정 코드가 실행되도록 설정한 것입니다.
2. const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
이 부분은 document.documentElement(HTML 요소)의 속성들을 구조 분해 할당 방식으로 가져옵니다. 각 속성의 의미는 다음과 같습니다:
- scrollTop:
- 현재 스크롤 위치를 나타냅니다. 페이지의 최상단에서부터 현재 보이는 위치까지의 픽셀 수입니다.
- 예를 들어, scrollTop이 100이라면 페이지 상단에서부터 100px 아래까지 스크롤된 상태입니다.
- scrollHeight:
- 전체 문서의 높이를 나타냅니다. 페이지의 총 높이이며, 스크롤되지 않은 부분을 포함합니다.
- 예를 들어, scrollHeight이 2000px이라면 문서 전체 높이가 2000px이라는 뜻입니다.
- clientHeight:
- 현재 화면에 보이는 높이입니다. 즉, 브라우저 창의 높이입니다.
- 예를 들어, clientHeight이 800px이라면, 현재 화면에 보이는 높이가 800px임을 나타냅니다.
3. if (scrollTop + clientHeight >= scrollHeight - 5 && !isLoading)
이 조건문은 사용자가 스크롤을 거의 바닥까지 내렸는지 확인하는 조건입니다.
- scrollTop + clientHeight:
- 스크롤된 높이(scrollTop)와 현재 화면에 보이는 높이(clientHeight)를 더하면, 사용자가 현재 화면에서 볼 수 있는 최하단 위치가 됩니다.
- scrollHeight - 5:
- 전체 문서의 높이에서 5px을 뺀 값입니다. 스크롤이 바닥에 도달했다고 간주하는 기준을 설정한 것입니다.
- -5로 여유를 둔 이유는 일부 브라우저에서 스크롤 위치의 부정확함 때문에 스크롤이 약간 부족하더라도 바닥에 도달한 것으로 인식하도록 하기 위해서입니다.
- 조건 확인:
- scrollTop + clientHeight >= scrollHeight - 5: 현재 스크롤 위치가 문서의 바닥(또는 그 근처)에 도달했음을 의미합니다.
- !isLoading: 현재 isLoading이 false일 때만 실행됩니다. 이는 데이터가 로드 중일 때 중복 요청이 발생하지 않도록 방지하는 역할입니다.
4. isLoading = true; // 로딩 중 상태로 변경
- 이 줄은 데이터를 로드 중임을 나타내기 위해 isLoading을 true로 설정합니다. 이제 추가 데이터가 로드되는 동안에는 다시 스크롤이 바닥에 도달해도 loadMore()가 재실행되지 않습니다.
jsp
<%
Connection conn = null; //DB 연결
PreparedStatement psmt = null; //SQL 등록 및 실행. 보안이 더 좋음!
ResultSet rs = null; //조회 결과를 담음
List<BoardVO> bList = new ArrayList<>();
//try 영역
try{
conn = DBConn.conn();
int indexpage = request.getParameter("indexpage") != null ? Integer.parseInt(request.getParameter("indexpage")) : 1;
int pageSize = 24;
int startRow = (indexpage - 1) * pageSize;
String sql = "select b.bno, pname "
+ "from board b "
+ "inner join attach a on b.bno = a.bno "
+ "where b.state='E' "
+ "order by bno desc "
+ "limit ? offset ?";
psmt = conn.prepareStatement(sql);
psmt.setInt(1, pageSize);
psmt.setInt(2, startRow);
rs = psmt.executeQuery();
%>
<section class="scrollable">
<div id="indexDiv">
<%
while(rs.next()){
%>
<div class="listDiv" id="<%= rs.getString("bno") %>">
<img style="width: 250px; height: 250px; border-radius: 20px;"
src="<%= request.getContextPath() %>/upload/<%= rs.getString("pname") %>">
</div>
<%
}
%>
</div>
</section>
<%
}catch(Exception e){
e.printStackTrace();
}finally{
try {
DBConn.close(rs, psmt, conn);
}catch(Exception e) {
e.printStackTrace();
}
}
%>
controller
public void loadMore(HttpServletRequest request
, HttpServletResponse response) throws ServletException, IOException {
Connection conn = null;
PreparedStatement psmt = null;
ResultSet rs = null;
int indexpage = request.getParameter("indexpage") != null ? Integer.parseInt(request.getParameter("indexpage")) : 1;
int pageSize = 24;
int startRow = (indexpage - 1) * pageSize;
JSONArray jsonArray = new JSONArray();
try {
conn = DBConn.conn();
String sql = "select b.bno, pname "
+ "from board b "
+ "inner join attach a on b.bno = a.bno "
+ "where b.state='E' "
+ "order by bno desc "
+ "limit ? offset ?";
psmt = conn.prepareStatement(sql);
psmt.setInt(1, pageSize);
psmt.setInt(2, startRow);
rs = psmt.executeQuery();
while (rs.next()) {
JSONObject jsonObj = new JSONObject();
jsonObj.put("bno", rs.getString("bno"));
jsonObj.put("pname", rs.getString("pname"));
jsonArray.put(jsonObj);
}
response.setContentType("application/json; charset=UTF-8");
response.getWriter().write(jsonArray.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
DBConn.close(rs, psmt, conn);
} catch (Exception e) {
e.printStackTrace();
}
}
}
현재 인덱스 페이지는 한 줄에 6개씩, 총 18개의 게시글이 들어갈 수 있는 크기인 상태에서 스크롤바를 만들기 위해
24개의 게시글이 처음 출력되게 설정하였다.
이후 스크롤 진행시 추가적으로 24개씩 조회하며 게시글이 추가된다
반응형
'JavaScript, jQuery, Ajax' 카테고리의 다른 글
[JS] 헤더부분 아이콘에 마우스 올라갈때 안내바나오고 원모양 나오게하기 (0) | 2024.10.30 |
---|---|
[JS] 회원가입,로그인 모달창에서 하기 (0) | 2024.10.29 |
[JS] 다크모드, 라이트모드 (0) | 2024.10.27 |
[Ajax] Ajax를 활용하여 요청페이지로 파라미터 보내기 (0) | 2024.09.11 |
[Ajax] XML과 Json 데이터 Ajax로 다루기 (1) | 2024.09.10 |