@mornya/scrolling-anchor-libs

The project of Scrolling Anchor UI library.

Usage no npm install needed!

<script type="module">
  import mornyaScrollingAnchorLibs from 'https://cdn.skypack.dev/@mornya/scrolling-anchor-libs';
</script>

README

Scrolling Anchor Libs

npm node types downloads license

The Scrolling Anchor UI module.

This project has been created by Vessel CLI. For a simple and quick reference about it, click here.

About

스크롤링 앵커로 지정된 각각의 HTML 요소(클라이언트들)을 화면 스크롤 위치에 따라 페이지 상단 및 하단 영역에 attach 혹은 detach 하도록 구현해주는 UI 라이브러리.

Installation

해당 모듈을 사용할 프로젝트에서는 아래와 같이 설치한다.

$ npm install --save @mornya/scrolling-anchor-libs
or
$ yarn add @mornya/scrolling-anchor-libs

Usage

SPA 형태 혹은 SSR 환경의 앱에서 사용이 가능하며, React.js / Vue.js 등의 라이프사이클과는 별개로 동작하므로 컴포넌트 mount 시점에 라이브러리를 초기화 하고 unmount 시점에 라이브러리를 해제 해주면 된다.

Required default style

라이브러리 내 SCSS 파일(@mornya/scrolling-anchor-libs/dist/scrolling-anchor.scss)이 반드시 적용되어야 하므로 해당 SCSS 파일을 import 해주거나, 참고하여 커스터마이징 후 적용해준다. 아래 스타일은 scrolling-anchor.scss 파일에 있는 내용으로, 기본적으로 적용되어야 제대로 동작한다.

$scrolling-anchor-zindex: 99;

.scrolling-anchor {
  & > * {
    display: inherit;
  }
  &[data-direction="top"] > .sa-attached,
  &[data-direction="bottom"] > .sa-attached {
    display: block;
    position: fixed;
    z-index: $scrolling-anchor-zindex;
  }
}

Vue.js example

<template>
  ...
  <div class="scrolling-anchor" data-direction="top"> <!-- "top" is default -->
    <nav>Top Navigation</nav>
  </div>
  ...
  <div
    class="scrolling-anchor"
    data-attach-delay="200"
    data-detach-delay="400"
  >
    <div>
      Top direction bar<br/>
      The styles will be applied after 200ms when attached<br/>
      also detached styles will be applied after 400ms
    </div>
  </div>
  ...
  <div class="scrolling-anchor" data-direction="bottom">
    <nav>Bottom Navigation</nav>
  </div>
  ...
</template>

<script>
import { ScrollingAnchor } from '@mornya/scrolling-anchor-libs';

export default {
  data () {
    return {
      saNav: null,
    };
  },
  updated () {
    if (!this.saNav) {
      this.saNav = new ScrollingAnchor();
    }
  },
  beforeDestroy () {
    this.saNav?.destroy();
  },
};
</script>

<style lang="scss">
  @import "~@mornya/scrolling-anchor-libs/dist/scrolling-anchor.scss";
</style>

React.js example

import React, { useRef, useEffect } from 'react';
import { ScrollingAnchor } from '@mornya/scrolling-anchor-libs';
import '@mornya/scrolling-anchor-libs/dist/scrolling-anchor.scss';

type Props = {};

const Navigation: React.FC<Props> = () => {
  const saNav = useRef<ScrollingAnchor | null>(null);

  useEffect(() => {
    if (!saNav.current) {
      saNav.current = new ScrollingAnchor('.scrolling-anchor', {
        onAttach (eventTarget) {
          console.log('Navigation attached:', eventTarget.el);
        },
        onDetach (eventTarget) {
          console.log('Navigation detached:', eventTarget.el);
        },
      });
    }
    return () => {
      // unmounted
      saNav.current?.destroy();
    };
  }, []); // mounted

  return (
    <>
      ...
      <div class="scrolling-anchor" data-direction="top"> <!-- "top" is default -->
        <nav>Top Navigation</nav>
      </div>
      ...
      <div
        class="scrolling-anchor"
        data-attach-delay="200"
        data-detach-delay="400"
      >
        <div>
          Top direction bar<br/>
          The styles will be applied after 200ms when attached<br/>
          also detached styles will be applied after 400ms
        </div>
      </div>
      ...
      <div class="scrolling-anchor" data-direction="bottom">
        <nav>Bottom Navigation</nav>
      </div>
    </>
  );
}

Attributes

data-attach-delay

해당 HTML 속성 값(숫자, > 0ms)이 지정된 ScrollingAnchor 영역은 상단 혹은 하단 화면영역에 attach 되려는 순간 .sa-child-will-attach 클래스가 추가되며, 지정한 값 만큼 시간이 지난 후 제거되면서 .sa-child-attached 클래스가 추가 된다. 동시에 실제 attach가 일어나는 .scrolling-anchor 클래스 하위 노드에는 .sa-will-attach 클래스가 추가되고 삭제되면서 .sa-attached 클래스가 추가된다.

트렌지션 등의 효과가 적용되는 시간만큼 해당 HTML 속성 값을 지정해주면 된다.

data-detach-delay

data-attach-delay 와는 반대로 detach 상황에 적용된다. .scrolling-anchor 클래스로 지정된 요소에는 .sa-child-will-detach 클래스가 추가되었다가 지정된 시간이 지난 후 삭제되며, 하위 노드에서는 .sa-will-detach 클래스가 추가되었다가 마찬가지로 삭제된다.

.sa-detached 같은 클래스는 생성되지 않으며, .sa-attached 클래스가 존재하면 attach 된 것이고 없으면 detach 된 것이다.

Options

스크롤링 앵커 라이브러리를 일반적으로 사용할 때는 별도의 옵션은 필요하지 않지만 화면이 동적으로 변화되는 경우에는 옵션을 통해 각 앵커 영역의 offset을 조정할 수 있다.

// 각 값들은 디폴트 설정 값임.
import { IScrollingAnchorEventTarget } from './ScrollingAnchor';

const option: IScrollingAnchorOption = {
  offsetAttachTop: 0,
  offsetAttachBottom: 0,
  onScroll: (nextOffset: number, prevOffset: number, maxOffset: number) => {},
  onAttach: (eventTarget: IScrollingAnchorEventTarget) => {},
  onDetach: (eventTarget: IScrollingAnchorEventTarget) => {},
};

offsetAttachTop

화면 상단에 앵커가 attach되는 시작 offset을 지정. 예를 들어 offsetAttachTop: 100 으로 지정하게 되면 앵커는 화면 상단 100px 지점부터 attach가 시작된다. 화면이 동적으로 변화되는 경우 컴포넌트 update 라이프사이클에 퍼블릭 메소드인 setPosition을 사용하여 동적으로 해당 값을 조정할 수 있다.

offsetAttachBottom

화면 하단에 앵커가 attach되는 시작 offset을 지정. offsetAttachTop 옵션과 마찬가지로 앵커가 화면 하단에 attach 되는 경우에 사용 가능하다.

onScroll

화면이 스크롤링 될 때 이벤트를 발생시키며 아래와 같은 파라미터 값을 제공하므로 사용자 콜백 함수를 만들어 처리 할 내용을 라이브러리에 제공해주면 된다.

function onScroll (nextOffset: number, prevOffset: number, maxOffset: number) {}
  • nextOffset: 화면 스크롤시 이동한 페이지 offset 값
  • prevOffset: 마지막으로 이동했던 페이지 offset 값이며, nextOffset 값과 비교하여 스크롤 하여 이동한 거리 및 방향을 알 수 있다.
  • maxOffset: 화면 상에서 이동 가능한 offset 값을 알 수 있다.

onAttach

각 앵커가 상/하단에 attach 되는 시점에 발생하는 이벤트.

function onAttach (eventTarget: IScrollingAnchorEventTarget) {}

eventTarget 객체:

  • el: attach 된 앵커 HTML 요소 객체.
  • direction: attach 된 앵커의 위치를 의미한다. class="scrolling-anchor"로 지정한 앵커 HTML 엘리먼트의 data-direction 값이다 (top or bottom)
  • lastIndex: data-direction 속성 값이 동일한 앵커 중의 몇 번 째 엘리먼트인지를 의미한다 (0부터 시작). 예를 들어 상단에 attach되는 앵커가 2개 일 경우 HTML 엘리먼트 순서대로 index 번호가 매겨져서 index는 각각 0과 1일 된다. 단 하단의 경우에는 역순으로 index 번호가 매겨진다 (마지막 앵커 index가 0).

onDetach

각 앵커가 attach 되는 시점을 벗어나 detach되어 원래 자리로 돌아가는 시점에 발생하는 이벤트.

function onDetach (eventTarget: IScrollingAnchorEventTarget) {}

eventTarget 객체:

  • el: detach 된 앵커 HTML 요소 객체.
  • direction: onAttach의 direction과 동일
  • lastIndex: onAttach의 index와 동일

Methods

getScrollOffsetY

현재 화면 스크롤 offset을 리턴해주는 static 메소드다.

function getScrollOffsetY (): nubmer {}

(예시)

console.log(ScrollingAnchor.getScrollOffsetY());

setPosition

동적으로 상/하단의 attach 시작 offset을 지정할 수 있다.

function setPosition (option: IScrollingAnchorPosition): void {}

option은 초기 ScrollingAnchor 생성시 사용한 옵션과 동일한 내용이지만 offsetAttachTop, offsetAttachBottom 두 값만 사용되어진다. 이 값을 하나 이상 넘겨주면 된다 (넘기지 않아도 무관).

scrollTo

지정한 HTML엘리먼트의 위치가 상단에 오도록 화면을 스크롤 한다.

function scrollTo (scrollOption: IScrollToOption): Promise<IScrollToResult | null> {}

(예시)

scrollTo({
  el: document.querySelector('#target-element'),
  marginTop: 10, // 해당 값만큼 아래 오프셋 위치로 오도록 지정 (default: 0)
  delay: 0, // 실제 스크롤을 해당 값만큼 지연 (milliseconds)
});

reset

DOM 랜더링 이후에 UI 변경이 있을 경우, 리스너 등 초기화가 불필요한 부분을 제외하고 각 스크롤링 앵커의 상태 등을 모두 초기화 한다.

function reset (): void {}

destroy

스크롤링 앵커 라이브러리에서 사용한 자원 및 리스너 등을 모두 해제할 때 사용. 컴포넌트의 unmount 혹은 destroy 라이프사이클이 진행되는 시점에 호출해주면 된다.

function destroy (): void {}

Change Log

프로젝트 변경사항은 CHANGELOG.md 파일 참조.

License

프로젝트 라이센스는 LICENSE 파일 참조.