자바스크립트 무한 스크롤 구현해보기

버건디·2022년 11월 17일
0
post-thumbnail

🔍 완성 화면

🔍 HTML 코드

<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <title>무한 스크롤</title>
</head>

<body>
    <h1>내 블로그</h1>
    <div class="mainContainer">
        <div class="filter-container">
            <input type="text" id="filter" class="filter" placeholder="Filter posts...">
        </div>
        <div class="posts-container" id="postContainer">

        </div>

        <div class="loadingContainer show" id="loadingContainer">
            <div class="circle"></div>
            <div class="circle"></div>
            <div class="circle"></div>
        </div>

    </div>

    <script src="main.js"></script>
</body>

</html>

🔍 CSS 코드

*{
    box-sizing: border-box;
}

body{
    height: 100vh;
    margin: 0;
    color: #fff;
    display: flex;
    flex-direction: column;
    align-items: center;
    background-color: rgb(146, 173, 235);
}

h1{
    text-align: center;
    margin-bottom: 0;
}


.mainContainer{
    margin: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}


.filter-container{
    width: 70%;
    margin-top: 20px;
}

.filter-container input{
    width: 100%;
    padding: 15px;
    border: 1px solid #fff;
    background-color: #fff;
    font-size: 16px;
    border-radius: 16px;
}

.filter-container input:focus{
    outline: 0;
}

.posts-container{
    width: 70%;

}


.posts{
    border: none;
    box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
    background-color: rgb(143, 143, 201);
    border-radius: 10px;
    margin: 60px 0;
    padding: 30px;
    display: flex;
    justify-content: center;
    align-content: center;
    position: relative;
}



.post-info{
    margin-left: 10px;
}

.post-title{
    margin-bottom: 10px;
    font-weight: bold;
    font-size: 24px;
}

.number{
    width: 50px;
    height:50px;
    border-radius: 50%;
    background-color: #fff;
    display: flex;
    justify-content: center;
    align-items: center;
    color: rgb(146, 173, 235);
    position: absolute;
    top: -30;
    left: -20;
}

.post-body{
    font-size: 16px;
}

.loadingContainer{
    width: 150px;
    height: 50px;
    display: none;
    justify-content: center;
    align-items: center;
}

.loadingContainer.show{
    display: flex;
}


.circle{
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background-color: #fff;
    margin: 5px;
    animation: transformY 0.7s infinite;

}

.circle:nth-child(2){
    animation-delay: 0.1s;
}

.circle:nth-child(3){
    animation-delay: 0.2s;
}


@keyframes transformY{
    0%, 100%{
        transform: translateY(0);
    }

    50%{
        transform: translateY(-10px);
    }
}

🔍 자바스크립트 코드

const filter = document.getElementById("filter");
const postContainer = document.getElementById("postContainer");
const loadingIcon = document.getElementById("loadingContainer");

let limit = 5;
let page = 1;


// 데이터 요청해오기 

const getRandomPost = async () => {
  const res = await fetch(
    `https://jsonplaceholder.typicode.com/posts?_limit=${limit}&_page=${page}`
  );

  const data = await res.json();
  console.log(data);

  addToDOMData(data);
};

// 데이터 브라우저에 띄우기 

const addToDOMData = (data) => {
  data.forEach((item) => {
    const post = document.createElement("div");
    post.classList.add("posts");

    post.innerHTML = `<div class="number">${item.id}</div>
    <div class="post-info">
        <div class="post-title">${item.title}
        </div>
        <div class="post-body">${item.body}
        </div>
    </div>`;

    postContainer.appendChild(post);
  });
};


//스크롤 이벤트


document.addEventListener("scroll", (e) => {
  const { clientHeight, scrollTop, scrollHeight } = e.target.scrollingElement;

  if (clientHeight + scrollTop >= scrollHeight) {
    setTimeout(() => {
      page++;
      getRandomPost();
    }, 500);
  }
});

//필터링 이벤트 

const filterPost = (e) => {
    const words = e.target.value;
    const posts = document.querySelectorAll(".posts");

    posts.forEach(post => {
        const title = post.querySelector('.post-title').innerText;
        const body = post.querySelector('.post-body').innerText;

       if(title.indexOf(words) > -1 || body.indexOf(words) > -1){
        post.style.display = 'flex';
       } else{
        post.style.display = 'none';
       }
    })
    
}

getRandomPost();


filter.addEventListener('input', filterPost);

✔️ 정리해야할 부분들

1. scrollTop, scrollHeight, clientHeight 의 차이점

scrollTop 은 글의 시작 위치부터 현재 화면에 보이는 부분 전까지의 길이이다.
scrollTop 을 통해 지금까지 스크롤을 해온 길이를 구할 수 있다.

scrollHeight 는 페이지 전체 글의 길이 이다.

clientHeight 는 현재 화면에서 보이는 높이이다.

그러므로 지금까지 스크롤 해온 길이와 현재 높이를 합했을때, 페이지 전체 글의 길이보다 길다면

스크롤 이벤트가 발생하게 된다.

document.addEventListener("scroll", (e) => {
  const { clientHeight, scrollTop, scrollHeight } = e.target.scrollingElement;

  if (clientHeight + scrollTop >= scrollHeight) {
    ....
  }
});

2. document.scrollingElement

document.scrollingElement는 문서를 스크롤하는 Element에 대한 참조값을 반환한다.

profile
https://brgndy.me/ 로 옮기는 중입니다 :)

0개의 댓글