컨텐츠로 건너뛰기

뷰 전환

Astro는 몇 줄의 코드만으로 뷰 전환을 지원합니다. 뷰 전환은 브라우저의 일반적인 전체 페이지 탐색 새로 고침 없이 페이지 콘텐츠를 업데이트하고 페이지 간 원활한 애니메이션을 제공합니다. 뷰 전환 API에 대한 브라우저 지원이 부족한 경우, Astro를 사용하면 모든 방문자에게 최상의 경험을 제공하기 위해 대체 전략을 제어할 수 있습니다.

Astro는 다른 페이지로 이동할 때 페이지 전환을 제어하기 위해 단일 페이지의 <head>에 추가할 수 있는 <ClientRouter /> 라우팅 컴포넌트를 제공합니다. 이는 탐색을 가로채고 페이지 간 전환을 사용자 정의할 수 있도록 하는 경량 클라이언트 측 라우터를 제공합니다.

전체 사이트에서 애니메이션 페이지 전환 (SPA 모드)을 사용하기 위해 공통 헤드 또는 레이아웃과 같은 재사용 가능한 .astro 컴포넌트에 이 컴포넌트를 추가합니다.

Astro의 뷰 전환 지원은 브라우저의 새로운 뷰 전환 API를 기반으로 하며 다음을 포함합니다.

페이지에 뷰 전환 추가

섹션 제목: 페이지에 뷰 전환 추가

<ClientRouter /> 라우팅 컴포넌트를 가져와 원하는 모든 페이지의 <head>에 추가하여 개별 페이지에서 뷰 전환을 사용합니다.

src/pages/index.astro
---
import { ClientRouter } from "astro:transitions";
---
<html lang="ko">
<head>
<title>나의 홈페이지</title>
<ClientRouter />
</head>
<body>
<h1>나의 웹사이트에 오신 것을 환영합니다!</h1>
</body>
</html>

전체 사이트 뷰 전환 (SPA 모드)

섹션 제목: 전체 사이트 뷰 전환 (SPA 모드)

공통 <head> 또는 공유 레이아웃 컴포넌트에 <ClientRouter /> 컴포넌트를 가져와서 추가합니다. Astro는 이전 페이지와 새 페이지 간의 유사성을 기반으로 기본 페이지 애니메이션을 생성하고 지원되지 않는 브라우저를 위한 대체 동작도 제공합니다.

아래 예시는 <CommonHead /> Astro 컴포넌트에 이 컴포넌트를 가져와 추가하여 Astro의 기본 페이지 탐색 애니메이션을 사이트 전체에 추가하는 방법을 보여줍니다. 여기에는 지원되지 않는 브라우저를 위한 기본 대체 제어 옵션도 포함됩니다.

src/components/CommonHead.astro
---
import { ClientRouter } from "astro:transitions";
---
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<!-- 기본 메타 태그 -->
<title>{title}</title>
<meta name="title" content={title} />
<meta name="description" content={description} />
<ClientRouter />

Astro의 기본 클라이언트 측 탐색을 활성화하는 데 다른 구성은 필요하지 않습니다!

더 세밀한 제어를 위해 개별 요소에서 전환 지시어를 사용하거나 기본 클라이언트 측 탐색을 재정의하세요.

Astro는 공유되는 고유한 view-transition-name을 이전 페이지와 새 페이지 모두에서 발견된 해당 요소에 자동으로 할당합니다. 이 일치하는 요소 쌍은 요소의 타입과 DOM에서의 위치에 의해 추론됩니다.

탐색 중 페이지 전환 동작을 더 세밀하게 제어하려면 .astro 컴포넌트의 페이지 요소에 선택적 transition:* 지시어를 사용하세요.

경우에 따라 해당 뷰 전환 요소를 직접 식별해야 할 수도 있습니다. transition:name 지시어를 사용하여 요소 쌍의 이름을 지정할 수 있습니다.

src/pages/old-page.astro
<aside transition:name="hero">
src/pages/new-page.astro
<aside transition:name="hero">

제공된 transition:name 값은 각 페이지에서 한 번만 사용할 수 있습니다. Astro가 적절한 이름을 유추할 수 없거나 일치하는 요소를 보다 세밀하게 제어하려는 경우 수동으로 직접 설정하세요.

추가된 버전: astro@2.10.0

transition:persist 지시어를 사용하여 페이지 탐색 간에 컴포넌트 및 HTML 요소를 교체하는 대신 유지할 수 있습니다.

예를 들어, 다음 <video>는 동일한 비디오 요소를 포함하는 다른 페이지로 이동할 때도 계속 재생됩니다. 이는 정방향 및 역방향 탐색 모두에서 작동합니다.

src/components/Video.astro
<video controls muted autoplay transition:persist>
<source
src="https://ia804502.us.archive.org/33/items/GoldenGa1939_3/GoldenGa1939_3_512kb.mp4"
type="video/mp4"
/>
</video>

client: 지시어를 사용하는 UI 프레임워크 컴포넌트인 Astro 아일랜드에 지시어를 배치할 수도 있습니다. 해당 컴포넌트가 다음 페이지에 존재하는 경우 새 페이지의 아일랜드로 교체하는 대신 현재 상태를 가진 이전 페이지의 아일랜드가 계속 표시됩니다.

아래 예시에서 transition:persist 속성을 가진 <Counter /> 컴포넌트를 포함하는 페이지를 앞뒤로 탐색할 때 컴포넌트의 내부 카운트 상태는 재설정되지 않습니다.

components/Header.astro
<Counter client:load transition:persist initialCount={5} />

아일랜드 또는 요소가 두 페이지 간의 다른 컴포넌트에 있는 경우 해당 요소를 수동으로 직접 식별할 수도 있습니다.

src/pages/old-page.astro
<video
controls
muted
autoplay
transition:name="media-player"
transition:persist
/>
src/pages/new-page.astro
<MyVideo
controls
muted
autoplay
transition:name="media-player"
transition:persist
/>

편리하게 transition:persist의 값으로 전환 이름을 사용할 수도 있습니다.

src/pages/index.astro
<video controls muted autoplay transition:persist="media-player">

추가된 버전: astro@4.5.0

탐색 시 아일랜드의 props를 유지할지 여부를 제어합니다.

기본적으로 아일랜드에 transition:persist를 추가하면 탐색 시 상태가 유지되지만 컴포넌트는 새 props를 사용하여 다시 렌더링됩니다. 예를 들어, 이는 컴포넌트가 현재 페이지의 title과 같은 페이지별 props를 수신할 때 유용합니다.

transition:persist 외에 transition:persist-props를 설정하여 이 동작을 재정의할 수 있습니다. 이 지시어를 추가하면 기존 상태를 유지하는 것 외에도 아일랜드의 기존 props를 유지합니다. (새 값을 사용하는 렌더링이 다시 발생하지 않습니다.)

내장 애니메이션 지시어

섹션 제목: 내장 애니메이션 지시어

Astro는 기본 fade 전환을 재정의하는 몇 가지 내장 애니메이션을 제공합니다. transition:animate 지시어를 개별 요소에 추가하여 특정 전환의 동작을 사용자 정의합니다.

  • fade (기본값): 사전 정의된 크로스페이드 애니메이션입니다. 이전 콘텐츠는 페이드 아웃되고 새 콘텐츠는 페이드 인됩니다.
  • initial: Astro의 사전 정의된 크로스페이드 애니메이션을 선택 해제하고 브라우저의 기본 스타일을 사용합니다.
  • slide: 이전 콘텐츠가 왼쪽으로 슬라이드 아웃되고 새 콘텐츠가 오른쪽에서 슬라이드 인되는 애니메이션입니다. 역방향 탐색 시 애니메이션은 반대로 동작합니다.
  • none: 브라우저의 기본 애니메이션을 비활성화합니다. 페이지의 모든 요소에 대한 기본 페이드를 비활성화하기 위해 페이지의 <html> 요소에 사용합니다.

지시어를 결합하여 페이지 애니메이션을 완벽하게 제어합니다. <html> 요소에 페이지 기본값을 설정하고 원하는 개별 요소를 재정의합니다.

아래 예시는 페이지의 나머지 부분에 대한 브라우저의 기본 페이드 애니메이션을 비활성화하면서 본문 콘텐츠에 대한 슬라이드 애니메이션을 생성합니다.

---
import CommonHead from "../components/CommonHead.astro";
---
<html transition:name="root" transition:animate="none">
<head>
<CommonHead />
</head>
<body>
<header>
...
</header>
<!-- 단일 요소의 페이지 기본값을 재정의합니다. -->
<main transition:animate="slide">
...
</main>
</body>
</html>

애니메이션 사용자 정의

섹션 제목: 애니메이션 사용자 정의

CSS 애니메이션 속성을 사용하여 전환의 모든 측면을 사용자 정의할 수 있습니다.

내장 애니메이션을 사용자 정의하려면 astro:transitions에서 애니메이션을 가져온 다음 사용자 정의 옵션을 전달합니다.

아래 예시는 내장된 fade 애니메이션의 지속 시간을 사용자 정의합니다.

---
import { fade } from "astro:transitions";
---
<header transition:animate={fade({ duration: "0.4s" })}>

다음 타입에 따라 정방향 및 역방향 동작과 새 페이지 및 이전 페이지를 모두 정의하여 transition:animate에 사용할 나만의 애니메이션을 정의할 수도 있습니다.

export interface TransitionAnimation {
name: string; // 키프레임의 이름입니다.
delay?: number | string;
duration?: number | string;
easing?: string;
fillMode?: string;
direction?: string;
}
export interface TransitionAnimationPair {
old: TransitionAnimation | TransitionAnimation[];
new: TransitionAnimation | TransitionAnimation[];
}
export interface TransitionDirectionalAnimations {
forwards: TransitionAnimationPair;
backwards: TransitionAnimationPair;
}

다음 예시는 루트 레이아웃 파일의 <style is:global> 태그에서 사용자 정의 bump 애니메이션을 정의하는 데 필요한 모든 속성을 보여줍니다.

src/layouts/Layout.astro
---
import { ClientRouter } from "astro:transitions";
---
<html lang="ko">
<head>
<ClientRouter />
</head>
<body>
<slot />
</body>
</html>
<style is:global>
@keyframes bump {
0% {
opacity: 0;
transform: scale(1) translateX(200px);
}
50% {
opacity: 0.5;
transform: scale(1.1);
}
100% {
opacity: 1;
transform: scale(1) translateX(0);
}
}
</style>

애니메이션의 동작은 애니메이션을 사용하는 모든 컴포넌트의 프런트매터에 정의되어야 합니다.

src/pages/index.astro
---
const anim = {
old: {
name: "bump",
duration: "0.5s",
easing: "ease-in",
direction: "reverse",
},
new: {
name: "bump",
duration: "0.5s",
easing: "ease-in-out",
},
};
const customTransition = {
forwards: anim,
backwards: anim,
};
---
<header transition:animate={customTransition}> ... </header>

사용자 정의 애니메이션을 정의할 때 매우 유연하게 작업할 수 있습니다. 원하는 결과를 얻기 위해 정방향 및 역방향에 다른 객체를 사용하거나 이전 및 새 페이지에 대해 별도의 키프레임 애니메이션을 제공하는 등 특이한 조합을 고려할 수 있습니다.

<ClientRouter /> 라우터는 다음을 수신하여 탐색을 처리합니다.

  • <a> 요소 클릭
  • 뒤로 및 앞으로 탐색 이벤트

다음 옵션을 사용하면 라우터에서 탐색이 발생하는 시점을 추가로 제어할 수 있습니다.

클라이언트 측 탐색 방지

섹션 제목: 클라이언트 측 탐색 방지

전체 페이지를 다시 로드하는 것을 방지하기 위해 관련된 두 페이지가 모두 <ClientRouter /> 라우터를 사용해야 하므로 클라이언트 측 라우팅을 통한 탐색이 불가능한 경우가 있습니다. 또한 모든 탐색 변경에서 클라이언트 측 라우팅을 원하지 않고 선택한 라우트에서 기존 페이지 탐색을 선호할 수도 있습니다.

data-astro-reload 속성을 <a> 또는 <form> 태그에 추가하여 링크별로 클라이언트 측 라우팅을 선택 해제할 수 있습니다. 이 속성은 기존 <ClientRouter /> 컴포넌트를 재정의하고 대신 탐색 중에 브라우저 새로 고침을 트리거합니다.

다음 예시는 홈페이지에서 아티클로 이동할 때만 클라이언트 측 라우팅을 방지하는 방법을 보여줍니다. 이렇게 하면 아티클 목록 페이지에서 동일한 페이지로 이동할 때는 히어로 이미지와 같은 공유 요소에 애니메이션을 적용할 수 있습니다.

src/pages/index.astro
<a href="/articles/emperor-penguins" data-astro-reload>
src/pages/articles.astro
<a href="/articles/emperor-penguins">

data-astro-reload 속성이 있는 링크는 라우터에서 무시되고 전체 페이지 탐색이 발생합니다.

navigate를 사용하여 일반적으로 <ClientRouter /> 라우터에서 수신하지 않는 이벤트를 통해 클라이언트 측 탐색을 트리거할 수도 있습니다. astro:transitions/client 모듈의 이 함수는 스크립트와 클라이언트 지시어로 하이드레이션된 프레임워크 컴포넌트에서 사용할 수 있습니다.

다음 예시는 방문자를 메뉴에서 선택한 다른 페이지로 이동시키는 Astro 컴포넌트를 보여줍니다.

src/components/Form.astro
<script>
import { navigate } from "astro:transitions/client";
// 선택한 옵션으로 이동합니다.
document.querySelector("select").onchange = (event) => {
let href = event.target.value;
navigate(href);
};
</script>
<select>
<option value="/play">시작</option>
<option value="/blog">블로그</option>
<option value="/about">소개</option>
<option value="/contact">연락처</option>
</select>
src/pages/index.astro
---
import Form from "../components/Form.astro";
import { ClientRouter } from "astro:transitions";
---
<html>
<head>
<ClientRouter />
</head>
<body>
<Form />
</body>
</html>

다음 예시는 React의 <Form /> 컴포넌트에서 navigate()를 사용하여 동일한 기능을 구현합니다.

src/components/Form.jsx
import { navigate } from "astro:transitions/client";
export default function Form() {
return (
<select onChange={(e) => navigate(e.target.value)}>
<option value="/play">시작</option>
<option value="/blog">블로그</option>
<option value="/about">소개</option>
<option value="/contact">연락처</option>
</select>
);
}

그러면 <Form /> 컴포넌트는 클라이언트 지시어와 함께 <ClientRouter /> 라우터를 사용하는 Astro 페이지에서 렌더링될 수 있습니다.

src/pages/index.astro
---
import Form from "../components/Form.jsx";
import { ClientRouter } from "astro:transitions";
---
<html>
<head>
<ClientRouter />
</head>
<body>
<Form client:load />
</body>
</html>

navigate 메서드는 다음 인수를 사용합니다.

  • href (필수) - 탐색할 새 페이지입니다.
  • options - 다음 속성을 가진 선택적 객체입니다.
    • history: "push" | "replace" | "auto"
      • "push": 라우터는 history.pushState를 사용하여 브라우저 기록에 새 항목을 만듭니다.
      • "replace": 라우터는 history.replaceState를 사용하여 탐색에 새 항목을 추가하지 않고 URL을 업데이트합니다.
      • "auto" (기본값): 라우터는 history.pushState를 시도하지만, URL이 전환할 수 없는 URL인 경우 브라우저 기록을 변경하지 않고 현재 URL을 유지합니다.
    • formData: POST 요청을 위한 FormData 객체입니다.

브라우저 기록을 통한 역방향 및 정방향 탐색을 위해 navigate()를 브라우저의 내장 함수인 history.back(), history.forward()history.go()와 결합할 수 있습니다. 컴포넌트의 서버 측 렌더링 중에 navigate()가 호출되면 아무런 효과가 없습니다.

브라우저 기록의 항목 바꾸기

섹션 제목: 브라우저 기록의 항목 바꾸기

일반적으로 탐색할 때마다 새 항목이 브라우저 기록에 추가됩니다. 이를 통해 브라우저의 뒤로앞으로 버튼을 사용하여 페이지 간 탐색이 가능합니다.

<ClientRouter /> 라우터를 사용하면 개별 <a> 태그에 data-astro-history 속성을 추가하여 기록 항목을 재정의할 수 있습니다.

data-astro-history 속성은 navigate() 함수의 history 옵션과 동일한 세 가지 값으로 설정할 수 있습니다.

data-astro-history: "push" | "replace" | "auto"

  • "push": 라우터는 history.pushState를 사용하여 브라우저 기록에 새 항목을 만듭니다.
  • "replace": 라우터는 history.replaceState를 사용하여 탐색에 새 항목을 추가하지 않고 URL을 업데이트합니다.
  • "auto" (기본값): 라우터는 history.pushState를 시도하지만, URL이 전환할 수 없는 URL인 경우 브라우저 기록을 변경하지 않고 현재 URL을 유지합니다.

다음 예제는 /main 페이지로 이동하지만 탐색 기록에 새 항목을 추가하지 않습니다. 대신 기록의 현재 항목 (/confirmation)을 재사용하고 이를 덮어씁니다.

src/pages/confirmation.astro
<a href="/main" data-astro-history="replace">

이렇게 하면 /main 페이지에서 뒤로 이동할 때 브라우저에 /confirmation 페이지가 표시되지 않고 그 이전 페이지가 표시되는 효과가 있습니다.

추가된 버전: astro@4.0.0

<ClientRouter /> 라우터는 <form> 요소에서 페이지 내 전환을 트리거하며 GETPOST 요청을 모두 지원합니다.

기본적으로 Astro는 methodPOST로 설정된 경우 양식 데이터를 multipart/form-data로 제출합니다. 웹 브라우저의 기본 동작과 일치시키려면 enctype 속성을 사용하여 application/x-www-form-urlencoded로 인코딩된 데이터를 제출하세요.

src/components/Form.astro
<form
action="/contact"
method="POST"
enctype="application/x-www-form-urlencoded"
>

data-astro-reload 속성을 사용하여 개별 양식의 라우터 전환을 선택 해제할 수 있습니다.

src/components/Form.astro
<form action="/contact" data-astro-reload>

<ClientRouter /> 라우터는 뷰 전환을 지원하는 브라우저 (예: Chromium 브라우저)에서 가장 잘 작동하지만 다른 브라우저에 대한 기본 대체 지원도 포함합니다. 브라우저가 뷰 전환 API를 지원하지 않더라도 Astro의 클라이언트 라우터는 대체 옵션 중 하나를 사용하여 브라우저 내 탐색을 제공할 수 있습니다.

브라우저 지원에 따라, 모든 브라우저에서 유사한 경험을 제공하기 위한 애니메이션 효과를 적용할 요소에 name 또는 animate 전환 지시어를 명시적으로 설정해야 할 수 있습니다.

src/pages/about.astro
---
import Layout from "../layouts/LayoutUsingClientRouter.astro";
---
<title transition:animate="fade">내 사이트에 대하여</title>

<ClientRouter /> 컴포넌트에 fallback 속성을 추가하고 이를 swap 또는 none으로 설정하여 Astro의 기본 대체 지원을 재정의할 수 있습니다.

  • animate (기본값, 권장): Astro는 페이지 콘텐츠를 업데이트하기 전에 사용자 정의 속성을 사용하여 뷰 전환을 시뮬레이션합니다.
  • swap: Astro는 페이지에 애니메이션 효과를 적용하지 않습니다. 대신 이전 페이지가 새 페이지로 즉시 교체됩니다.
  • none: Astro는 애니메이션 페이지 전환을 전혀 수행하지 않습니다. 대신 지원하지 않는 브라우저에서 전체 페이지 탐색을 수행합니다.
---
import { ClientRouter } from "astro:transitions";
---
<title>나의 사이트</title>
<ClientRouter fallback="swap" />

클라이언트 측 탐색 프로세스

섹션 제목: 클라이언트 측 탐색 프로세스

<ClientRouter /> 라우터를 사용할 때, Astro의 클라이언트 측 탐색을 생성하기 위해 다음 단계가 발생합니다.

  1. 사이트 방문자가 다음 작업 중 하나를 통해 탐색을 트리거합니다.

    • 사이트의 다른 페이지에 내부적으로 연결되는 <a> 태그를 클릭합니다.
    • 뒤로 버튼을 클릭합니다.
    • 앞으로 버튼을 클릭합니다.
  2. 라우터가 다음 페이지를 가져오기 시작합니다.

  3. 라우터는 HTML 요소에 data-astro-transition 속성을 추가하고, 이 속성의 값을 "forward" 또는 "back"으로 설정합니다.

  4. 라우터는 document.startViewTransition을 호출합니다. 이는 브라우저 자체의 뷰 전환 프로세스를 트리거합니다. 중요한 것은 브라우저가 페이지의 현재 상태를 스크린샷한다는 것입니다.

  5. startViewTransition 콜백 내부에서 라우터는 다음 이벤트 시퀀스로 구성된 교체 (swap)를 수행합니다.

    • <head>의 콘텐츠가 교체되지만, 다음과 같은 일부 요소는 유지됩니다.

      • 스타일시트 DOM 노드가 새 페이지에 존재하는 경우, FOUC를 방지하기 위해 유지됩니다.
      • 스크립트가 새 페이지에 존재하는 경우 유지됩니다.
      • transition:persist가 있는 다른 헤드 요소는 해당 요소가 새 페이지에도 존재하는 경우 유지됩니다.
    • <body>는 새 페이지의 요소로 완전히 교체됩니다.

    • transition:persist로 표시된 요소는 해당 요소가 새 페이지에도 존재하는 경우 새 DOM으로 이동합니다.

    • 필요한 경우 스크롤 위치가 복원됩니다.

    • astro:after-swap 이벤트가 document에서 트리거됩니다. 이는 교체 (swap) 프로세스의 끝입니다.

  6. 라우터는 전환을 해결하기 전에 새 스타일시트가 로드될 때까지 기다립니다.

  7. 라우터는 페이지에 추가된 새 스크립트를 실행합니다.

  8. astro:page-load 이벤트가 발생합니다. 이는 탐색 프로세스의 끝입니다.

뷰 전환 시 스크립트 동작

섹션 제목: 뷰 전환 시 스크립트 동작

기존 Astro 프로젝트에 뷰 전환을 추가하면 일부 스크립트는 전체 페이지 새로 고침 때와 달리 페이지 탐색 후 다시 실행되지 않을 수 있습니다. 다음 정보를 사용하여 스크립트가 예상대로 실행되는지 확인하세요.

<ClientRouter /> 컴포넌트를 사용하여 페이지 간을 탐색할 때 스크립트는 브라우저 동작과 일치하도록 순차적으로 실행됩니다.

Astro의 기본 스크립트인 번들링된 모듈 스크립트는 한 번만 실행됩니다. 초기 실행 후에는 전환 후 새 페이지에 스크립트가 존재하더라도 무시됩니다.

번들링된 모듈 스크립트와 달리 인라인 스크립트는 여러 번 방문한 페이지에 존재하는 경우, 사용자가 사이트를 방문하는 동안 다시 실행될 가능성이 있습니다. 인라인 스크립트는 방문자가 스크립트 없는 페이지로 이동했다가 스크립트가 존재하는 페이지로 다시 돌아오면 다시 실행될 수도 있습니다.

뷰 전환을 사용하면 일부 스크립트는 전체 페이지 새로 고침 때와 달리 페이지 탐색 후 다시 실행되지 않을 수 있습니다. 클라이언트 측 라우팅 중 발생하는 여러 이벤트를 감지하고, 해당 이벤트가 발생할 때 특정 동작을 실행할 수 있습니다. 기존 스크립트를 이벤트 리스너로 래핑하여 탐색 주기에서 적절한 타이밍에 실행할 수 있습니다.

다음 예제는 페이지 탐색이 끝날 때 실행되는 astro:page-load에 대한 이벤트 리스너에 모바일 “햄버거” 메뉴에 대한 스크립트를 래핑하여 새 페이지로 이동한 후 메뉴를 클릭했을 때 반응하도록 만듭니다.

src/scripts/menu.js
document.addEventListener("astro:page-load", () => {
document.querySelector(".hamburger").addEventListener("click", () => {
document.querySelector(".nav-links").classList.toggle("expanded");
});
});

다음 예제는 새 페이지가 이전 페이지를 대체한 직후, 그리고 DOM 요소가 화면에 그려지기 전에 발생하는 astro:after-swap 이벤트에 대한 응답으로 실행되는 함수를 보여줍니다. 새 페이지가 렌더링되기 전에 다크 모드 테마를 확인하고 필요한 경우 설정하여 페이지 이동 후 라이트 모드 테마가 깜박이는 것을 방지합니다.

src/components/ThemeToggle.astro
<script is:inline>
function applyTheme() {
localStorage.theme === "dark"
? document.documentElement.classList.add("dark")
: document.documentElement.classList.remove("dark");
}
document.addEventListener("astro:after-swap", applyTheme);
applyTheme();
</script>

추가된 버전: astro@4.5.0

모든 전환 후에 인라인 스크립트가 다시 실행되도록 하려면 data-astro-rerun 속성을 추가하세요. 스크립트에 속성을 추가하면 암시적으로 is:inline도 추가되므로 Astro에서 번들링 및 처리되지 않은 스크립트에만 사용할 수 있습니다.

<script is:inline data-astro-rerun>...</script>

클라이언트 측 탐색 중에 페이지가 로드될 때마다 스크립트가 실행되도록 하려면 수명 주기 이벤트에 의해 실행되어야 합니다. 예를 들어 DOMContentLoaded에 대한 이벤트 리스너는 astro:page-load 수명 주기 이벤트로 대체될 수 있습니다.

인라인 스크립트에 전역 상태를 설정하는 코드가 있는 경우, 이 상태는 스크립트가 두 번 이상 실행될 수 있다는 점을 고려해야 합니다. <script> 태그에서 전역 상태를 확인하고 가능한 경우 코드를 조건부로 실행합니다. window가 유지되기 때문에 이 방법이 작동합니다.

<script is:inline>
if (!window.SomeGlobal) {
window.SomeGlobal = {};
}
</script>

<ClientRouter /> 라우터는 탐색 중에 document에서 여러 이벤트를 발생시킵니다. 이러한 이벤트는 탐색 수명 주기에 대한 훅을 제공하여 새 페이지가 로드 중임을 나타내는 요소를 표시하거나, 기본 동작을 재정의하거나, 탐색이 완료될 때 상태를 복원하는 등의 작업을 수행할 수 있도록 합니다.

탐색 프로세스에는 새 콘텐츠가 로드되는 준비 단계, 이전 페이지의 콘텐츠가 새 페이지의 콘텐츠로 대체되는 DOM 교체 단계, 스크립트가 실행되고 로딩이 완료된 것으로 보고되며 정리 작업이 수행되는 완료 단계가 포함됩니다.

Astro의 뷰 전환 API 수명 주기 이벤트는 순서대로 다음과 같습니다.

일부 작업은 모든 이벤트 중에 트리거될 수 있지만, 최상의 결과를 위해 일부 작업은 특정 이벤트 중에만 수행할 수 있습니다. 예를 들어 준비 전에 로딩 스피너를 표시하거나 콘텐츠 교체 전에 애니메이션 쌍을 재정의하는 경우가 있습니다.

추가된 버전: astro@3.6.0

탐색이 시작된 후 (예: 사용자가 링크를 클릭한 후), 콘텐츠가 로드되기 전 준비 단계의 시작 부분에서 발생하는 이벤트입니다.

이 이벤트는 다음과 같은 용도로 사용됩니다.

  • 로딩이 시작되기 전에 로딩 스피너를 표시하는 등의 작업을 수행합니다.
  • 외부 URL이 아닌 템플릿에 정의된 콘텐츠를 로드하는 등 로딩을 변경합니다.
  • 사용자 정의 애니메이션을 위해 탐색 direction (일반적으로 forward 또는 backward)을 변경합니다.

다음은 콘텐츠가 로드되기 전에 스피너를 로드하고 로드 직후 중지하기 위해 astro:before-preparation 이벤트를 사용하는 예시입니다. 이러한 방식으로 loader 콜백을 사용하면 코드의 비동기 실행이 가능합니다.

<script is:inline>
document.addEventListener("astro:before-preparation", (event) => {
const originalLoader = event.loader;
event.loader = async function () {
const { startSpinner } = await import("./spinner.js");
const stop = startSpinner();
await originalLoader();
stop();
};
});
</script>

추가된 버전: astro@3.6.0

새 페이지의 콘텐츠가 로드되어 문서로 구문 분석된 후 준비 단계의 끝에서 발생하는 이벤트입니다. 이 이벤트는 뷰 전환 단계 전에 발생합니다.

이 예제에서는 astro:before-preparation 이벤트를 사용하여 로딩 표시기를 보여주기 시작하고 astro:after-preparation 이벤트를 사용하여 중지합니다.

<script is:inline>
document.addEventListener("astro:before-preparation", () => {
document.querySelector("#loading").classList.add("show");
});
document.addEventListener("astro:after-preparation", () => {
document.querySelector("#loading").classList.remove("show");
});
</script>

이것은 위 예제보다 스피너를 불러오는 더 간단한 버전입니다. 리스너의 모든 코드를 동기적으로 실행할 수 있다면 loader 콜백에 연결할 필요가 없습니다.

추가된 버전: astro@3.6.0

준비 단계에서 채워진 새 문서가 현재 문서를 대체하기 전에 발생하는 이벤트입니다. 이 이벤트는 뷰 전환 내부에서 발생하며, 사용자는 여전히 이전 페이지의 스냅샷을 보고 있습니다.

이 이벤트는 교체 전에 변경 사항을 생성하는 데 사용할 수 있습니다. 이벤트의 newDocument 속성은 들어오는 문서를 나타냅니다. 다음은 localStorage의 브라우저 라이트 또는 다크 모드 기본 설정을 새 페이지로 전달하는 예시입니다.

<script is:inline>
function setDarkMode(document) {
let theme = localStorage.darkMode ? "dark" : "light";
document.documentElement.dataset.theme = theme;
}
setDarkMode(document);
document.addEventListener("astro:before-swap", (event) => {
// 들어오는 문서를 전달하여 테마를 설정합니다.
setDarkMode(event.newDocument);
});
</script>

astro:before-swap 이벤트는 교체의 구현을 변경하는 데에도 사용할 수 있습니다. 기본 교체 구현은 헤드 콘텐츠를 변경하고, 이전 문서에서 유지되는 요소를 newDocument로 이동한 다음, 전체 body를 새 문서의 요소로 바꿉니다.

수명 주기의 이 시점에서, 기존 문서의 전체 콘텐츠를 변경하는 등 (일부 다른 라우터가 수행하는 작업) 나만의 교체 구현을 정의하도록 선택할 수 있습니다.

<script is:inline>
document.addEventListener("astro:before-swap", (event) => {
event.swap = () => {
diff(document, event.newDocument);
};
});
</script>

사용자 정의 교체 함수 구현

섹션 제목: 사용자 정의 교체 함수 구현

추가된 버전: astro@4.15.0

astro:transitions/client 모듈의 swapFunctions 객체는 문서 속성, 페이지 요소 및 스크립트 실행 처리를 포함하여 특정 교체 관련 작업을 처리하는 5가지 유틸리티 함수를 제공합니다. 이러한 함수는 사용자 정의 교체 구현을 정의하는 데 직접 사용할 수 있습니다.

다음 예제는 이러한 함수를 사용하여 Astro의 내장 교체 구현을 재현하는 방법을 보여줍니다.

<script>
import { swapFunctions } from "astro:transitions/client";
// `window.document`를 `doc`으로 대체합니다.
function mySwap(doc: Document) {
swapFunctions.deselectScripts(doc);
swapFunctions.swapRootAttributes(doc);
swapFunctions.swapHeadElements(doc);
const restoreFocusFunction = swapFunctions.saveFocus();
swapFunctions.swapBodyElement(doc.body, document.body);
restoreFocusFunction();
}
event.swap = () => mySwap(event.newDocument);
<script>

사용자 정의 교체 구현은 이 템플릿으로 시작하고, 필요에 따라 개별 단계를 사용자 정의 논리로 추가하거나 대체할 수 있습니다.

새 페이지가 이전 페이지를 대체한 직후 발생하는 이벤트입니다. document에서 이 이벤트를 수신하고 새 페이지의 DOM 요소가 렌더링되고 스크립트가 실행되기 전에 발생하는 작업을 트리거할 수 있습니다.

나가는 페이지에서 수신될 때, 이 이벤트는 새 페이지로 전달해야 하는 DOM의 상태를 전달하고 복원하는 데 유용합니다.

예를 들어, 이는 다크 모드 클래스 이름 (<html class="dark-mode">)을 추가할 수 있는 안전한 수명 주기의 최신 시점이지만, 이전 이벤트에서 그렇게 하는 것이 좋습니다.

astro:after-swap 이벤트는 브라우저 기록이 업데이트되고 스크롤 위치가 설정된 직후에 발생합니다. 따라서 이 이벤트를 대상으로 하는 한 가지 용도는 기록 탐색에 대한 기본 스크롤 복원을 재정의하는 것입니다. 다음 예제는 각 탐색에 대해 가로 및 세로 스크롤 위치를 페이지의 왼쪽 상단 모서리로 재설정합니다.

document.addEventListener("astro:after-swap", () =>
window.scrollTo({ left: 0, top: 0, behavior: "instant" }),
);

새 페이지가 사용자에게 표시되고 차단 스타일 및 스크립트가 로드된 후 페이지 탐색이 끝날 때 발생하는 이벤트입니다. document에서 이 이벤트를 수신할 수 있습니다.

<ClientRouter /> 컴포넌트는 사전 렌더링된 페이지의 초기 페이지 탐색과 이후의 모든 탐색 (앞으로 또는 뒤로)에서 이 이벤트를 발생시킵니다.

이 이벤트를 사용하면 모든 페이지 탐색에서 코드를 실행할 수 있습니다. 예를 들어 탐색 중에 손실될 수 있는 이벤트 리스너를 설정할 수 있습니다.

<script>
document.addEventListener("astro:page-load", () => {
// 첫 페이지 로딩 시와 모든 탐색 후에 실행됩니다.
setupStuff(); // 예: 이벤트 리스너 추가
});
</script>

클라이언트 측 라우팅을 활성화하고 페이지 전환에 애니메이션을 적용하는 것은 모두 접근성 문제를 동반하며, Astro는 뷰 전환을 사용하는 사이트를 가능한 한 기본적으로 접근 가능하게 만드는 것을 목표로 합니다.

추가된 버전: astro@3.2.0

<ClientRouter /> 컴포넌트는 클라이언트 측 라우팅 중 페이지 탐색을 위한 경로 알림 기능을 포함합니다. 이를 활성화하기 위한 구성이나 작업은 필요하지 않습니다.

보조 기술은 탐색 후 새 페이지 제목을 알림으로써 방문자에게 페이지가 변경되었음을 알립니다. 기존 전체 페이지 브라우저 새로 고침을 사용하는 서버 측 라우팅을 사용하는 경우 새 페이지가 로드된 후 기본적으로 이 작업이 수행됩니다. 클라이언트 측 라우팅에서는 <ClientRouter /> 컴포넌트가 이 작업을 수행합니다.

클라이언트 측 라우팅에 라우트 알림을 추가하기 위해 컴포넌트는 aria-live 속성이 assertive로 설정된 요소를 새 페이지에 추가합니다. 이는 AT (보조 기술)에 즉시 알리도록 지시합니다. 컴포넌트는 알림 텍스트를 결정하기 위해 우선 순위 순으로 다음을 확인합니다.

  • <title> (존재하는 경우)
  • 첫 번째 <h1>
  • 페이지의 pathname

접근성을 위해 각 페이지에 항상 <title>을 포함하는 것을 강력히 권장합니다.

Astro의 <ClientRouter /> 컴포넌트는 prefer-reduced-motion 설정이 감지될 때마다 대체 애니메이션을 포함하여 모든 뷰 전환 애니메이션을 비활성화하는 CSS 미디어 쿼리를 포함합니다. 대신 브라우저는 애니메이션 없이 DOM 요소를 간단히 교체합니다.

기여하기 커뮤니티 후원하기