Scroll 이벤트를 활용한 스크롤 구현

2020. 6. 25. 17:13웹/Javascript

스크롤 이벤트 발생 시 데이터르 조회 하기 참조되는 객체

HTML Element 객체

  • offset  

    • offsetHeight/offsetWidth : 해당 엘리먼트의 너비와 높이(border, padding, scroll 포함, margin 제외)

    • offsetParent : offsetLeft, offsetTop의 기준이 되는 부모 엘리먼트

    • offsetLeft/offsetTop : offsetParent 기준으로 한 엘리먼트 위치 좌표

  • scroll 

    • scrollWidth/scrollHeight : 해당 엘리먼트의 넓이와 높이
                                       (overflow: scroll 인 경우 화면에 보이지 않는 스크롤영역까지 포함되기 때문에 offsetWidth/offsetHieght 값보다 scoll의 값이 더 크게 됨)

    • scrollLeft/scrollTop : 스크롤된 x,y 좌표

  • client

    • clientWidth/clientHeight : 타겟 엘리먼트인 클라이언트 영역의 넓이와 높이(border, margin 제외한 내부 넓이와 높이)

    • clientLeft/clientTop : 타겟 엘리먼트인 클라이언트의 borer 값과 동일

 

 

Document 객체의 위치 프로퍼티와 메서드

  • HTMLElment 의 body 프로퍼터인 scrollWidth, scrollHeight 를 이용하여 넓이와 높이를 구할 수 있음

  • document.body.scrollWidth : Document 영역의 전체 넓이(브라우저에 스크롤이 있다면 window 창보다 document 가 더 큼)

  • document.body.scrollHeight: Document 영역의 전체 높이

 

 

 

 

구현 

  • 로드 후 window에 scroll Event 등록

  • 크롤이 포함된 높이 - 윈도우 뷰포트의 높이 < 스크롤이 진행된 높이 이면 FetchData

 

index.html

  • content 영역 안의 loader div 영역을 viewport 와의 교차 지점 대상

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script type="text/javascript" src="./scollTest.js"></script>
    <style>
        h3 {
            text-align: center;
        }

        li {
            list-style: none;
            width: 100%;
            height: 50px;
            line-height: 50px;
            border: 1px solid;
        }

        .loader {
            height: 20px;
            width: 100%;
        }
    </style>
</head>

<body>
    <div class="header">
        <h3>Scroll Event를 활용한 스크롤 구현</h3>
    </div>
    <div class="content">
        <ul></ul>
        <div class="loader"></div>
    </div>
</body>
</html>

 

scorllTest.js

window.onload = function () {
    const count = 30;
    let index = 0;

    function getScrollTop() {
        // pageYOffset : 문서가 수직으로 얼마나 스크롤됐는지 픽셀 단위로 반환
        // document.documentElement :  문서의 루트 요소를 나타내는 Element를 반환
        // scollTop : 세로로 스크롤되는 픽셀 수를 가져 오거나 설정, 요소의 scrollTop값은 요소의 상단에서 맨 위에 보이는 내용 까지의 거리
        // 크로스 브라우징 이슈로인해 document.documentElement, document.body.parentNode, document.body 로 표현
        return (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
    }

    function getDocumentHeight() {
        const body = document.body;
        const html = document.documentElement;

        // scrollHeight : 수직 스크롤바가 있는 엘리먼트(element)의  CSS 높이를 초과하여, 보이지 않는 부분까지 포함한 내용(content)의 높이(height)
        // offsetHeight : 수직 패딩 및 경계를 포함하는 요소의 높이
        // clientHeight : 엘리먼트의 내부 높이를 픽셀로 반환. 내부 여백(padding)을 포함하지만, 수평 스크롤바의 높이, 경계선, 또는 외부 여백(margin)은 포함하지 않음
        return Math.max(
            body.scrollHeight, body.offsetHeight,
            html.clientHeight, html.scrollHeight, html.offsetHeight
        );
    };

    const fetchData = () => {
        return new Promise((resolve, reject) => {
            document.querySelector(".loader").innerHTML = "loading ...";

            setTimeout(() => {
                const container = document.querySelector(".content>ul");
                const fragment = document.createDocumentFragment();
                for (let i = index; i < index + count; i++) {
                    const item = document.createElement("li");
                    item.innerHTML = `text - ${i}`;
                    fragment.appendChild(item);
                }
                container.appendChild(fragment);
                index += count;
            }, 500);
        });
    };

    window.addEventListener('scroll', function () {
        // 스크롤이 포함된 높이 - 윈도우 뷰포트의 높이 < 스크롤이 진행된 높이 이면 FetchData
        // window.innerHeight : 윈도우의 레이아웃 뷰포트 높이를 픽셀 단위로 나타내는 정수 값
        if (getScrollTop() < getDocumentHeight() - window.innerHeight) return;
        fetchData();
    });

    fetchData();
};

 

 

 

 

 

 

참고 

https://webclub.tistory.com/104

 

' > Javascript' 카테고리의 다른 글

IntersectionObserver 활용한 스크롤 구현  (0) 2020.06.26
이벤트 전달 방식(버블링, 캡처, 위임)  (0) 2020.06.15
call, apply, bind 메서드  (0) 2020.03.10
스코프와 클로저  (0) 2020.03.05
스코프 체인  (0) 2020.03.05