Svelte 앱: Svelte/모션을 사용하여 Loading Overlay 구성 요소 생성

내 프로젝트 중 하나에서 로딩이 완료될 때까지 앱을 숨기기 위해 로딩 오버레이 구성 요소를 만들어야 했습니다. 이 기사에서는 내가 한 방법을 공유하고 싶습니다.

먼저 HTML 및 CSS 마크업을 스케치해 보겠습니다. 이것은 매우 간단합니다. 블록을 만들고 위치를 고정한 다음 전체 화면 크기로 늘리고 콘텐츠를 중앙에 배치합니다. svg 그래디언트를 사용하여 텍스트를 다른 색상으로 채우는 방법에 주목하십시오.

<div class="overlay">
    <svg width="115" height="32" viewBox="0 0 78 32" xmlns="http://www.w3.org/2000/svg">
        <defs>
            <linearGradient id="filler">
                <stop offset="50%" stop-color="#ff006e" />
                <stop offset="50%" stop-color="white" />
            </linearGradient>
        </defs>

        <text x="0" y="24px" fill="url(#filler)">Loading...</text>
    </svg>
</div>

<style>
  .overlay {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 10001;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #3a86ff;
    font-family: "Arial", sans-serif;
    font-size: 1.375rem;
  }
</style>




시원한. 마크업이 끝났습니다. 이제 애니메이션으로 넘어 갑시다. 이를 위해 표준 Svelte 도구를 사용합니다. tweened에서 svelte/motion 을 사용하여 progress 변수를 만들고 해당 값을 svg 그래디언트에 사용합니다.

const progress = tweened(0, { easing: linear, duration: 3000 });



  <linearGradient id="filler">
    <stop offset={`${$progress}%`} stop-color="#ff006e" />
    <stop offset={`${$progress}%`} stop-color="white" />
  </linearGradient>


다음으로 구성 요소가 마운트될 때 호출할 함수animate를 생성해 보겠습니다. 애니메이션이 무한정 계속되도록 이 함수를 재귀적으로 만듭니다. 다른 재귀 함수와 마찬가지로 종료 지점이 있어야 합니다. 따라서 메모리 누수를 방지하기 위해 구성 요소 인스턴스가 소멸될 때 함수 실행이 종료되도록 합니다.

  let destroyed = false

  async function animate() {
    if (destroyed) {
      return
    }

    await width.set(100)
    await width.set(0, { duration: 0 })
    await animate()
  }

  onMount(() => {
    animate()
  })

  onDestroy(() => {
    destroyed = true
  })




괜찮은. 우리 구성 요소는 이미 좋아 보입니다. 이제 결과 애니메이션을 2단계로 만들어 개선할 것입니다. 첫 번째 단계에서는 흰색 텍스트를 분홍색으로 칠하고 그 반대의 경우도 마찬가지입니다. 2단계에서는 분홍색 텍스트를 흰색으로 칠합니다. 이를 위해 애니메이션의 현재 단계를 나타내는 데 사용할 부울 값이 있는 writable 저장소를 생성합니다. animate 함수를 호출할 때마다 이 값을 반대로 변경합니다.

  const isFirstStage = writable(true)

  async function animate() {
    if (destroyed) {
      return
    }

    await width.set(100)
    await width.set(0, { duration: 0 })
    isFirstStage.update((value) => !value)
    await animate()
  }



<linearGradient id="filler">
  <stop offset={`${$progress}%`} stop-color={$isFirstStage ? '#ff006e' : 'white'} />
  <stop offset={`${$progress}%`} stop-color={$isFirstStage ? 'white' : '#ff006e'} />
</linearGradient>




따라서 로딩 표시기 구성 요소 자체는 끝났습니다. 이제 지표를 사용하는 여러 구성 요소가 있을 수 있다고 상상해 봅시다. 각각에서 오버레이를 렌더링할 수 있지만 접근 방식을 더 개선하고 표시기를 한 번 렌더링하고 표시기를 켜고 끄는 기능을 제공할 수 있는 기능을 만들어 보겠습니다. 이를 위해 표시기를 표시하라는 요청을 포함하는 다른writable 상점을 생성합니다. 상점에 요청이 하나 이상 남아 있는 한 표시기 자체가 렌더링됩니다.

import { writable, derived } from "svelte/store";
import { nanoid } from "nanoid";

export const loadingOverlayQueue = writable([]);

export function showLoadingOverlay() {
  const newRequestId = nanoid();

  loadingOverlayQueue.update((currentValue) => [...currentValue, newRequestId]);

  return newRequestId;
}

export function hideLoadingOverlay(requestId) {
  loadingOverlayQueue.update((currentValue) =>
    currentValue.filter((item) => item !== requestId)
  );
}

export const isLoadingOverlayShown = derived(
  loadingOverlayQueue,
  (requests) => requests.length > 0
);




이제 모두 완료되었습니다. 몇 가지 간단한 단계를 거쳐 원본 애니메이션 로딩 표시기를 만들었습니다. 소스 코드는 my GitHub에서 찾을 수 있습니다. 날렵한 작업을 즐기십니까?

좋은 웹페이지 즐겨찾기