티스토리 뷰

📌 HTML 


구현 

   - 1) post 내용을 스크롤바 하면 보여질 수 있도록 

   - 2) 로딩 되는 표시 구현

 

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover"
    />
    <title>무한 스크롤바</title>
    <link rel="stylesheet" href="../../utils/reset.css" />
    <link rel="stylesheet" href="style.css" />
  </head>

  <body>
    <div class="wrap">
      <h2>무한 스크롤바</h2>
      <div class="posts"></div> <!-- post 내용 담기 -->
      <div class="loader">      <!-- 로딩 되는 부분 -->
        <div></div>
        <div></div>
        <div></div>
        <div></div>
      </div>
    </div>
    <script src="script.js"></script>
  </body>
</html>

 

 

📌 CSS


 

body {
  background-color: #a5e1b9;
}

.wrap {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: 2rem 0;
}

h2 {
  font-size: 3rem;
  font-weight: 900;
  text-align: center;
  padding: 2rem 0;
  color: #1f6c38;
}

/**** post 부분 ****/
.posts {
  width: 100%;
  max-width: 700px;
  margin: 0 auto;
  padding: 0 3rem;
}

.post {
  margin: 1rem 0;
  background-color: rgb(255 255 255 / 80%);
  border-radius: 0.5rem;
  padding: 1rem;
  border: 0.5rem solid white;
  box-shadow: 10px 14px 20px rgb(137 137 137 / 20%);
}

.header {
  display: flex;
  font-size: 1.5rem;
  color: #1f6c37;
  font-weight: 700;
  text-transform: uppercase;
}

.id {
  font-size: 1rem;
  padding-right: 1rem;
}

.body {
  padding-top: 1rem;
}

/****************/

/**** post 요청시 로딩 되는 부분 ****/
.loader {
  display: inline-block;
  position: relative;
  width: 80px;
  height: 80px;
  opacity: 0;
}

.loader.show {
  opacity: 1;
}

.loader div {
  position: absolute;
  top: 33px;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: #fff;
  animation-timing-function: cubic-bezier(0, 1, 1, 0);
}

.loader div:nth-child(1) {
  left: 8px;
  animation: loader1 0.6s infinite;
}

.loader div:nth-child(2) {
  left: 8px;
  animation: loader2 0.6s infinite;
}

.loader div:nth-child(3) {
  left: 32px;
  animation: loader2 0.6s infinite;
}

.loader div:nth-child(4) {
  left: 56px;
  animation: loader3 0.6s infinite;
}

@keyframes loader1 {
  0% {
    transform: scale(0);
  }

  100% {
    transform: scale(1);
  }
}

@keyframes loader3 {
  0% {
    transform: scale(1);
  }

  100% {
    transform: scale(0);
  }
}

@keyframes loader2 {
  0% {
    transform: translate(0, 0);
  }

  100% {
    transform: translate(24px, 0);
  }
}

/****************/

 

 

📌 자바스크립트


 - scrollTop: top 스크롤 높이

 - clientHeight: 현재 바라보고 있는 스크롤 높이

 - scrollHeight: 화면에서 생성된 전체 스크롤 높이

; (function () {
  'use strict'

  const get = function (target) {
    return document.querySelector(target)
  }

  let currentPage = 1
  let total = 10
  const limit = 10
  const end = 100  //총갯수

  const $posts = get('.posts')
  const $loader = get('.loader')

  // 데이터 로딩이 완료되면 hide
  const hideLoader = () => {
    $loader.classList.remove('show')
  }

  // 데이터 로딩시 불러오는 css
  const showLoader = () => {
    $loader.classList.add('show')
  }


  //포스트 보여주는 CSS
  const showPosts = (posts) => {
    posts.forEach((post) => {
      const $post = document.createElement('div')
      $post.classList.add('post')
      $post.innerHTML = `
          <div class="header">
            <div class="id">${post.id}.</div>
            <div class="title">${post.title}</div>
          </div>
          <div class="body">${post.body}</div>
      `
      $posts.appendChild($post)
    })
  }

  //포스트 요청 
  const getPosts = async (page, limit) => {
    const API_URL = `https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=${limit}`
    const response = await fetch(API_URL)
    if (!response.ok) {
      throw new Error('에러가 발생했습니다.')
    }
    return await response.json()
  }

  //포스트 로딩
  const loadPosts = async (page, limit) => {
    showLoader()
    try {
      const response = await getPosts(page, limit);
      showPosts(response)
    } catch (error) {
      console.error(error.message);
    } finally {
      hideLoader()
    }
  }

  //스크롤 제어 
  const handleScroll = () => {
    const { scrollTop, scrollHeight, clientHeight } = document.documentElement
    if (total === end) {
      //scroll event 멈춤
      window.removeEventListener('scroll', handleScroll)
      return
    }

    if (scrollTop + clientHeight >= scrollHeight - 5) {
      currentPage++
      total += 10
      loadPosts(currentPage, limit)
      return
    }
  }

  //초기시작
  window.addEventListener('DOMContentLoaded', () => {
    loadPosts(currentPage, limit)
    window.addEventListener('scroll', handleScroll)
  })
})()
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
글 보관함