[무한스크롤] infinite scroll

youngseo·2022년 3월 3일
0

JS프로젝트

목록 보기
14/18
post-thumbnail

무한스크롤

1. 무한스크롤이란?

무한 스크롤은 사용자가 페이지 하단에 도달했을 때, API가 호출되며 콘텐츠가 계속 로드되는 사용자 경험(UX) 방식입니다. 한 페이지 아래로 스크롤 하면 끝없이 새로운 화면을 보여주게 되고 이로 인해 많은 양의 콘텐츠를 스크롤 해서 볼 수 있습니다.

2.API 연동

https://jsonplaceholder.typicode.com/

  • 프로토타이핑용 api
  • /posts 활용
  • json-server 만든 곳에서 만들었기 때문에 사용 방법은 json-server와 동일

3. removeEventListener

https://developer.mozilla.org/ko/docs/Web/API/EventTarget/removeEventListener

  • addEventListener()로 등록했던 이벤트 리스너를 제거
  • 더이상 필요가 없는데 이벤트가 계속 발생하는 경우 메모리 누수가 일어날 수 있음
  • 따라서 명시적으로 해제

실습

1. 기본 틀 작성

;
(function () {
  'use strict'

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

  })
})()

2 외부 데이터 가져오기

;
(function () {
  'use strict'

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

  //API url 불러오기
  const getPost = async () => {
    const API_URL = 'https://jsonplaceholder.typicode.com/posts'
    const response = await fetch(API_URL) // async await를 사용하면 변수에 담을 수 있습니다
    if (!response.ok) {
      throw new Error('에러')
    }
    return await response.json()
  }

  const loadPost = async () => {
    const response = await getPost() //리턴한 response.json을 받아옴
  }

  window.addEventListener('DOMContentLoaded', () => { //DOMContentLoaded발생시 실행
    loadPost()
  })
})()

DOMContentLoaded정리 필요

async await 정리 필요 (붙이는 이유?)

3. 받아온 데이터 하나하나 보여주기

3-1 showPost()

  const showPosts = (posts) => {
    posts.forEach((post) => {
      const $post = document.createElement('div')
      $post.classList.add('post')
      $post.innerHTML = `
      <div class="header">
        <div class="id"></div>
        <div class="title"></div>
      </div>
      <div class="body">
      
      </div>
      `
    });
  }

  const loadPost = async () => {
    const response = await getPost() //리턴한 response.json을 받아옴
    showPosts(response)
  }

3-2 posts에 데이터 넣기

  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>
      `
    });

3-3 appendchild

  const $posts = get('.posts')

    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)
    });
  }
  

4. 페이지 끝 체크해서 데이터 추가로 가져오기

4-1 가지고 오는 데이터 10개로 제한하기

  const limit = 10

  const getPost = async () => {
    const API_URL = `https://jsonplaceholder.typicode.com/posts?_limit=${limit}`
   ...
  } 

4-2 scroll 끝 감지

  const onScroll = () => {
    const {scrollTop, scrollHeight, clientHeight} = document.documentElement

    if (scrollTop + clientHeight >= scrollHeight - 5) { //간격을 주기 위해 5px을 뺍니다.
    loadPost()      
    }
  }

  window.addEventListener('DOMContentLoaded', () => { 
    loadPost()
    window.addEventListener('scroll', onScroll)
  })
})()

4-3 감지가 되면 페이지 추가

  let page = 1

  //API url 불러오기
  const getPost = async () => {
    const API_URL = `https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=${limit}`
    ...
  }
    
   const onScroll = () => {
    const {scrollTop, scrollHeight, clientHeight} = document.documentElement

    if (scrollTop + clientHeight >= scrollHeight - 5) { //간격을 주기 위해 5px을 뺍니다.
      page++
    loadPost()      
    }
  }   

4-4 100개를 다 불러오면 더 불러오지 않도록 제한 설정

  const end = 100
  let total = 10
  
    const onScroll = () => {
    const {scrollTop, scrollHeight, clientHeight} = document.documentElement

    if(total === end) {
      return
    }
    if (scrollTop + clientHeight >= scrollHeight - 5) { //간격을 주기 위해 5px을 뺍니다.
      page++
      total += 10
      loadPost(currentPage, limit)
      return
    }
  }

4-5 page를 다 불러오면 scroll이벤트 제거

    if(total === end) {
      window.removeEventListener('scroll', onScroll)
      return
    }

5. 로딩애니메이션 노출

try, catch문

  const $loader = get('.loader')
  
  const showLoader = () => {
    $loader.classList.add('show')
  }

  const hideLoader = () => {
    $loader.classList.remove('show')
  }

  const loadPost = async () => {
    //로딩 엘레멘트를 보여줌
    showLoader()
    try {
      const response = await getPost() //리턴한 response.json을 받아옴
      showPosts(response)
    } catch (error) {
      console.error(error)
    } finally {
      hideLoader()
      //로딩 엘레멘트를 사라지게 함
    }
  }  

0개의 댓글