javascript - naver 오픈소스, egjs 라이브러리 활용하기 (flicking & infinitegrid)

정현우·2024년 2월 26일
6
post-thumbnail

egjs 라이브러리

NAVER에서 제공하는 라이브러리로 인터랙티브한 컨텐츠를 만드는데 특화된 라이브러리다. 사실 공식 릴리즈 된지는 꽤 되어서 이미 많은 사람들이 사용하는듯 하다. 해당 라이브러리를 vanilla js 로 바로 사용해보자!

egjs ?!

  • 태초 공개할 때는 Jindo 프레임워크(과거 NAVER에서 제공하던 js 라이브러리)부터 쌓인 노하우를 녹였다고 한다! naver jindo 는 이제 역사의 뒤안길로 사양된 웹 FE 프레임워크 이며, 이걸 사용 했다거나 기억한다면,, 당신은,,,,!! NHN의 안과 밖: Jindo와 jQuery 을 읽어 보셔야 합니다 ㅎ 나의 시대는 아니지만 가끔 이렇게 유물을 가져오는 재미가 쏠쏠합니다. ㅎ 🫡

  • egjs"네이버의 FE 오픈소스 컴포넌트 그룹" 이며 미디엄 naver-fe-platform 에서도 소식을 볼 수 있다. 그리고 gihubofficial docs 에서 확인할 수 있 듯, 되게 일관되게 정리가 잘 되어 있고 잘 관리되는 중인 것을 볼 수 있다.

  • egjs 의 공식 공개는 [ jQuery 기반의 egjs 라이브러리를 공개합니다. ] 글에서 맛볼 수 있다. [ egjs 2023년 4분기 릴리즈 소식을 전해드립니다. ] 글에서 보면 21, 22, 23년도 가파른 상승세를 보여주는 것을 볼 수 있다.

  • docs가 굉장히 잘되어있어서 특별한 가이드 없이 바로 따라서 사용할 수 있다!

1) flicking 사용하기

  • 캐러셀(Carousel)은 사전적으로는 "회전목마" 라고 하며, 이미지나 텍스트의 슬라이드를 가로로 슬라이드시켜 여러 개를 표시하는 컴포넌트를 말한다.

  • 요즘 이런 캐러셀을 0 부터 직접 만드는 일은 "흔하지 않는 것" 같다. 특정 니즈에 의해서나, 브랜딩 관점에서의 디자인 템플릿이 완전하게 정해지지 않으면 거의 라이브러리를 활용하게 된다.

flicking

  • 이런 Carousel 컴포넌트를 만드는 library 이며 egjs 에서는 간판인 프로젝트 이다. "Everyday 30 million people experience" 라고 소개 되어 있다.

  • 타 라이브러리 대비 강점은 "크로스 프레임워크" 이다.

  • 기본적으로 vanilla javascript (물론 typscript 는 사용하는 듯 하다.) 로 짜여져 있고, 이를 다른 framework 에서 적용하기 위해 Adapter pattern 으로 배포해 프레임워크 전용 컴포넌트와 동일한 사용성과 동작방식을 가지게 한 것이다.

  • 일단 도입이 굉장히 편하다. 데모 페이지 에서 보고 바로 쉽게 활용할 수 있다.

<!-- EGJS flicking CDN -->
<link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/egjs-flicking/4.11.2/flicking.css"
      crossorigin="anonymous"
      />
<script
        src="https://cdnjs.cloudflare.com/ajax/libs/egjs-flicking/4.11.2/flicking.pkgd.min.js"
        crossorigin="anonymous"
></script>
<div id="flick" class="flicking-viewport">
  <div class="flicking-camera">
    <div class="flicking-panel">1</div>
    <div class="flicking-panel">2</div>
    <div class="flicking-panel">3</div>
    <div class="flicking-panel">4</div>
    <div class="flicking-panel">5</div>
  </div>
</div>
<div class="block is-flex is-justify-content-center">
  <span id="btn-prepend" class="button mr-2 is-info is-outlined">Prepend</span>
  <span id="btn-append" class="button mr-2 is-info is-outlined">Append</span>
</div>
const flicking = new Flicking("#flick", {
  renderOnlyVisible: true
});
let minIdx = 1;
let maxIdx = 5;

const prependBtn = document.querySelector("#btn-prepend");
const appendBtn = document.querySelector("#btn-append");

prependBtn.addEventListener("click", () => {
  flicking.prepend(`<div class="flicking-panel">${--minIdx}</div>`)
});
appendBtn.addEventListener("click", () => {
  flicking.append(`<div class="flicking-panel">${++maxIdx}</div>`)
});

  • "화면에서 보이는 부분" 만 랜더링 되며 다른 <div class="flicking-panel"> 들은 dynamic rendering 이 된다.

Nested Flickings

  • 개인적으로 flicking 안에 다시 flicking 을 배치하는데 아주 안정감(?)이 있다고 생각이 된다.
<div id="flick1" class="flicking-viewport">
  <div class="flicking-camera">
    <div class="flicking-panel">1</div>
    <div class="flicking-panel nested-wide">
      <div id="flick2" class="flicking-viewport">
        <div class="flicking-camera">
          <div class="flicking-panel">2.1</div>
          <div class="flicking-panel">2.2</div>
          <div class="flicking-panel">2.3</div>
        </div>
      </div>
    </div>
    <div class="flicking-panel nested-wide vertical">
      <div id="flick3" class="flicking-viewport vertical">
        <div class="flicking-camera">
          <div class="flicking-panel">3.1</div>
          <div class="flicking-panel">3.2</div>
          <div class="flicking-panel">3.3</div>
        </div>
      </div>
    </div>
    <div class="flicking-panel">4</div>
    <div class="flicking-panel">5</div>
  </div>
</div>
const flicking1 = new Flicking("#flick1");
const flicking2 = new Flicking("#flick2", {
  bounce: 0,
  bound: true,
  nested: true,
});
const flicking3 = new Flicking("#flick3", {
  bounce: 0,
  // bound: true,
  nested: true,
  horizontal: false,
});
  • 실제 예제에는 <div class="flicking-camera">...</div> 이 빠져있는데, 공식 홈페이지에는 해당 div 가 빠져있으면 캐러셀 이벤트가 작동을 안하더라..!

  • 여튼 이렇게 Nested 한 형태로 flicking-viewport 안에 다시 flicking-viewport 안에 다시 flicking-viewport 를 주면서 동시에 vertical 로 다양한 형태의 중첩 캐러셀을 심플하게 구현할 수 있음이 좋았다.

  • 근데 bound 값을 주니까 작동을 안하고,, vertical 에서 왜 첫 번째 친구가 표현되지 않는지,, css issue 인지,,

  • 사실 이렇게 바닐라 js 에서 바로 활용하려고 보니 아직 핵심 class 인자 값 (flicking-panel, nested-wide, vertical, flicking-camera 등) 이 와닿지가 않는다..!

수직 캐러셀 응용

<div id="flick4" class="flicking-viewport vertical">
  <div class="flicking-camera">
    <div class="flicking-panel">One</div>
    <div class="flicking-panel">Two</div>
    <div class="flicking-panel">Three</div>
    <div class="flicking-panel">Four</div>
    <div class="flicking-panel">Five</div>
    <div class="flicking-panel">Six</div>
  </div>
</div>
const flicking4 = new Flicking("#flick4", {
  circular: true,
  horizontal: false,
});

// Simple AutoPlay function
setInterval(function () {
  flicking4.next().catch(() => {}); // Ignore errors
}, 2000); // Change slide every 2 seconds
  • flicking-plugin 이 따로 있으며 여기서 AutoPlay 를 통해 자동 넘기기를 구현할 수 있다.

  • 하지만 CDN 으로 바로 사용하는 것은 지원하지 않기에 직접 소스 코드 내장하기 싫어서, setInterval 과 함께 간단하게 flicking4.next().catch... 로 구현할 수 있다.

  • official docs 에서는 이런 리스트 형식, 날씨와 같은, 자동 넘기기를 심플하게 구현할때 아주 요긴하게 쓸만하다.

  • 여기서 꼭 주의할 점은 [ Sum of panel sizes - panel size >= viewport size ] 이 지켜져야 circular: true, 이 제대로 작동한다는 점!!

  • 그 외 실제로 사용하는 예제들이나 시선을 사로잡는 캐로셀 컴포넌트 Flicking 을 소개합니다 에서 실전 flicking 예시를 좀 더 많이 살펴볼 수 있다!!

2) infinitegrid 사용하기

  • flicking 만큼 사랑받는 infinitegrid 라는 라이브러리도 있다. 물론 flicking 자체에서도 Grid 로 활용해 배치하는 방법도 있지만, pinterest 가 아래와 같이 배치하는 이미지 방식, 그리고 "무한 스크롤" 을 구현하는 것은 좀 귀찮다.

  • 그리고 이미지 사이징을 고려하면서 배치하는 것 역시 귀찮고, 때에 따라 다르게 보여주고자 하면 배보다 배꼽이 큰 느낌이 있다.

  • Naver D2 - 카드형 UI와 eg.InfiniteGrid 3.0 에서 이런 고민의 흔적을 볼 수 있으며, 이에 따라 우리는 InfiniteGrid 를 잘 찍어먹을 수 있게 되었다.

Masonry

  • Masonry 의 사전적 의미는 벽돌을 쌓아올린다는 뜻으로, 웹에서의 Masonry 레이아웃은 하나의 축(대부분 열)이 일반적인 그리드 레이아웃을 사용하고 다른 한 축이 Masonry 레이아웃을 사용하는 레이아웃 방법을 말한다. (아래 사진)

GridLayout - MasonryInfiniteGrid

  • Masonry 배치 컨셉을 new InfiniteGrid.MasonryInfiniteGrid 로 구현할 수 있다. - Docs 가이드 페이지, 실제 구현된 데모 페이지

  • 테스트용으로 많은 랜덤 이미지도 제공해줘서 편하다 ㅎ, 그리고 최소한의 css를 좀 먹여야 적용되는걸 편하게 볼 수 있으니 이점 유의! (item 자체의 width 를 안주면 이미지 크기에 따라 width 가 꽉 차버릴 수 있다!)

<!-- EGJS infinitegrid CDN -->
<script src="https://unpkg.com/@egjs/infinitegrid/dist/infinitegrid.min.js"></script>
<style>
  .container {
  margin: 50px;
  }
  .item {
  width: 250px;
  }
  .item img {
  width: 100%;
  }
</style>
<div class="container"></div>
function getItems(nextGroupKey, count) {
  const nextItems = [];

  for (let i = 0; i < count; ++i) {
    const num = nextGroupKey * count + i;
    nextItems.push(`
      <div class="item">
        <div class="thumbnail">
          <img src="https://naver.github.io/egjs-infinitegrid/assets/image/${
            (num % 33) + 1
          }.jpg" alt="egjs" />
        </div>
        <div class="info">egjs ${num}</div>
      </div>
	`);
  }
  return nextItems;
}

const ig = new InfiniteGrid.MasonryInfiniteGrid(".container", {
  gap: 5,
});

ig.on("requestAppend", (e) => {
  const nextGroupKey = (+e.groupKey || 0) + 1;
  ig.append(getItems(nextGroupKey, 10), nextGroupKey);
});
ig.renderItems();
  • 좀 더 직관적이다. container div 안에 dynamic 하게 item 을 dynamic 하게 만들어서 만든 배열을 return 하는 함수 getItems 를 활용한다.

  • 위와 같이 기가 막힌 "무한 스크롤" + "Masonry" 가 만들어 졌다.

  • "스켈레톤 컴포넌트, Skeleton UI" 와 같은 "컴포넌트 미리보기, loading 되는 것 처럼", "Placeholder" 를 추가할 수 있다.

ig.setPlaceholder({
  html: `<div class="placeholder"></div>`,
});

ig.on("requestAppend", (e) => {
  const nextGroupKey = (+e.groupKey || 0) + 1;

  e.wait();
  e.currentTarget.appendPlaceholders(5, nextGroupKey);
  setTimeout(() => {
    e.ready();
    ig.append(getItems(nextGroupKey, 10), nextGroupKey);
  }, 1000);
});
ig.renderItems();

그 외

  • JustifiedInfiniteGrid 와 같이 이미지를 배열에 맞춰, 이미지도 비율에 맞게 리사이징 된 상태로 배치하는 것도 있으며

  • FrameInfiniteGrid, PackingInfiniteGrid 와 같이 정해진 비율, 마치 css grid 사용하는 것과 같은 효과를 내는 패턴도 가능하다.

  • 데모가 잘되어 있으니 꼭 살펴보는 것을 추천한다! 위에서 사용한 코드 데모 결과는 아래 2개 링크에서 바로 확인 가능하다!

  1. egjs - Flicking
  2. egjs - Infinitegrid

마무리

  • naver 가 사내 library를 확장해 global open source 까지 만들고 관리하는 것을 보면, 국내에서는 그래도 오픈 소스 개발 생태계에 가장 활발하지 않는가 생각이 든다.

  • 메인테이너도 활발하고issues 피드백도 빠른것 같다. 더욱이 test code 의 coverage 도 같이 신경쓰고 있으며 글 작성 시점 기준, flicking 은 80% 이상의 test code coverage 를 보여주고 있다.

  • 또, EGJS 에 "I'm Ready!" 와 같은 심플하지만 활용할만한 라이브러리도 많다.

  • 최근에 쓴 글이 너무 무겁기도 했고, 요즘 "개발"보다 너무 코딩에만 몰두한 것 같아 self refresh 할 겸 light한 library를 다뤄본다.


출처

profile
도메인 중심의 개발, 깊이의 가치를 이해하고 “문제 해결” 에 몰두하는 개발자가 되고싶습니다. 그러기 위해 항상 새로운 것에 도전하고 노력하는 개발자가 되고 싶습니다!

2개의 댓글

comment-user-thumbnail
2024년 3월 3일

오늘도 재밌게 읽었어요!

1개의 답글