데이터 레이지 로딩

by hohoya33

HTML

<div id="viewport"></div>


<div id="target">
    <div class="card">
        <figure class="card-image loading"></figure>
        <div class="card-detail">
            <div class="card-mall loading"></div>
            <div class="card-title loading"></div>
            <div class="card-price loading"></div>
        </div>
    </div>
</div>

<p id="statusBox" class="yes">
  isIntersecting === <span id="statusText">true</span>
</p>

SCSS

html {
  height: 200%;
  min-height: 400px;
  font-family: sans-serif;
  padding-top: 3.5em; }

#viewport {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  margin: 0;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  cursor: default;
  background: #dae1e7;
}

#target {
  position: relative; 
  width: 232px;
  margin: 100vh auto 100vh;
}

#statusBox {
  position: fixed;
  top: 0;
  left: 1em;
  right: 1em;
  font-family: monospace;
  padding: 0.5em;
  background-color: #ff8;
  border: 3px solid #cc5;
  opacity: .9; 
  text-align: center;
}

#statusBox.yes {
  background: #8f8;
  border-color: #5c5; }

#statusBox.no {
  background: #f88;
  border-color: #c55; }




.card {
  overflow: hidden;
  background: white;
  border-radius: .25rem;
  max-width: 232px;
  width: 232px;
}

.card-detail {
  padding: .5rem 1rem;
  height: 84px;
}

.card-image {position:relative;display:block;padding-bottom:100%;overflow:hidden;margin:0;}
.card-image img {position:absolute;left:0;top:0;width:100%;height:auto}


.loading {
  position: relative;
  background-color: #E2E2E2;
  &::after {
    display: block;
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    transform: translateX(-100%);
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .2), transparent);
    animation: loading 1.5s infinite;
  }
}

.card-mall.loading {
    width:100px;
    height:10px;
    margin:16px 0;
}

.card-title.loading {
    width:180px;
    height:8px;
    margin-bottom:8px;
}

.card-price.loading {
    width:180px;
    height:8px;
    margin-bottom:8px;
}


@keyframes loading {
  100% {
    transform: translateX(100%);
  }
}


@keyframes Gradient {
    0% {
        background-position: 0% 50%
    }
    50% {
        background-position: 100% 50%
    }
    100% {
        background-position: 0% 50%
    }
}

.lazyloading img{display:block}

JavaScript

const cardImage = document.querySelector('.card-image');
const cardMall = document.querySelector('.card-mall');
const cardTitle = document.querySelector('.card-title');
const cardPrice = document.querySelector('.card-price');



const renderCard = () => {
  cardTitle.textContent = '국산 라지자 캔들 아로마 향초 캔들워머';
  cardMall.textContent = '이마트몰';
  cardPrice.textContent = '8,910 원~';
  createImage();

  cardTitle.classList.remove('loading');
  cardMall.classList.remove('loading');
  cardPrice.classList.remove('loading');
  cardImage.classList.remove('loading');
};

function createImage() {
  const img = new Image();
  img.classList.add("image");
  img.setAttribute('alt', '국산 라지자 캔들 아로마 향초 캔들워머');
  img.setAttribute('src', 'http://item.ssgcdn.com/31/37/76/item/1000031763731_i2_500.jpg');
  cardImage.appendChild(img);
}


function removeCard() {
    cardImage.innerHTML = '';
    cardTitle.textContent = '';
    cardMall.textContent = '';
    cardPrice.textContent = '';

    cardTitle.classList.add('loading');
    cardMall.classList.add('loading');
    cardPrice.classList.add('loading');
    cardImage.classList.add('loading');
}


var statusBox = document.getElementById("statusBox");
var statusText = document.getElementById("statusText");

function handler(entries, observer) {
  for (entry of entries) {
    console.log(entry);

    statusText.textContent = entry.isIntersecting;

    if (entry.isIntersecting) {
      statusBox.className = "yes";
      setTimeout(() => {
       renderCard();
      }, 1000);
    } else {
      statusBox.className = "no";
      removeCard();
    }
  }
}

let observer = new IntersectionObserver(handler);
observer.observe(document.getElementById("target"));