首页 / Svelte 5 入门教程 / in:/out: 过渡

Svelte 5 入门教程

in:/out: 过渡

本教程共 50 篇 · 第 24 篇 · 更新于 2026-08-05 · 约 6 分钟阅读

SvelteSvelte 5inout过渡动画

本节目标:学会用 in: 和 out: 指令为元素设置不同的进入和离开动画,理解它与 transition: 的区别,掌握 local 修饰符和全局过渡的用法。

in: 和 out: 的区别

上一章学的 transition: 是双向的——进入和离开用同一种动画,而且可以中途逆转。in:out: 则把进入和离开拆开了,可以分别设置不同的效果。

打个比方,transition: 像自动门——进出都是同一扇门缓缓打开。in:out: 像旋转门配滑梯——进门用旋转门,出门直接滑走,两套不同的效果。

<script>
	import { fade, fly } from 'svelte/transition';

	let visible = $state(false);
</script>

<label>
	<input type="checkbox" bind:checked={visible} />
	显示/隐藏
</label>

{#if visible}
	<!-- 进入时飞入,离开时淡出 -->
	<div in:fly={{ y: 200 }} out:fade>
		飞入,淡出
	</div>
{/if}

transition: vs in:/out:

关键区别在于”中途逆转”的行为。

当你用 transition: 时,如果元素正在进入过程中你突然让它离开,动画会逆转方向——原本淡入到一半,会从当前位置淡出。

in:out: 时则不会逆转。如果进入动画还没播完就被打断,离开动画会从头开始播放。

对比项transition:in: + out:
方向双向,可逆转单向,不可逆转
灵活性进出相同效果进出可不同
中途打断逆转动画重新开始

搭配不同效果

in:out: 最大的价值就是进出可以用完全不同的动画。

<script>
	import { fly, scale, slide } from 'svelte/transition';

	let visible = $state(false);
</script>

<button onclick={() => visible = !visible}>切换</button>

{#if visible}
	<div
		in:fly={{ x: -100, duration: 500 }}
		out:scale={{ start: 0.5, duration: 300 }}
		style="padding: 20px; background: #eee;"
	>
		从左边飞入,缩放着离开
	</div>
{/if}

只用 in: 或只用 out:

你可以只写 in: 不写 out:,或者反过来。没写的那一方就没有过渡效果。

<script>
	import { fade } from 'svelte/transition';

	let visible = $state(false);
</script>

{#if visible}
	<!-- 只有进入动画,离开时瞬间消失 -->
	<div in:fade={{ duration: 1000 }}>
		只有淡入,没有淡出
	</div>
{/if}

自定义过渡函数签名

无论是 transition:in: 还是 out:,自定义过渡函数的签名是一样的。

type Transition = (
	node: HTMLElement,
	params: any,
	options: { direction: 'in' | 'out' | 'both' }
) => {
	delay?: number;
	duration?: number;
	easing?: (t: number) => number;
	css?: (t: number, u: number) => string;
	tick?: (t: number, u: number) => void;
};

第三个参数 options 包含 direction 字段,告诉你当前是进入(in)、离开(out)还是双向(both)。你可以根据方向返回不同的配置。

<script>
	function smartTransition(node, params, { direction }) {
		if (direction === 'in') {
			return {
				duration: 800,
				css: (t) => `opacity: ${t}; transform: translateY(${(1 - t) * 50}px)`
			};
		} else {
			return {
				duration: 300,
				css: (t) => `opacity: ${t}; transform: scale(${t})`
			};
		}
	}

	let visible = $state(false);
</script>

{#if visible}
	<div in:smartTransition out:smartTransition>
		进入和离开用不同效果
	</div>
{/if}
Note

虽然 in:out: 可以分别指定同一个函数,但如果函数内部已经根据 direction 区分了行为,用 transition:smartTransition 更简洁。

local 修饰符

过渡默认是”本地”的。什么意思呢?看这个嵌套结构:

{#if x}
	{#if y}
		<p transition:fade>只在 y 变化时播放</p>
	{/if}
{/if}

xtrue 变成 false 时,内层 {#if y} 整体被移除。但 <p> 的过渡不会播放,因为它只在自己所属的 y 块创建/销毁时播放。

如果你希望父块销毁时也播放过渡,加 |global 修饰符:

{#if x}
	{#if y}
		<!-- 本地:只在 y 变化时播放 -->
		<p transition:fade>本地过渡</p>

		<!-- 全局:x 或 y 变化时都播放 -->
		<p transition:fade|global>全局过渡</p>
	{/if}
{/if}
Tip

local 是默认行为,不需要显式写。大多数场景用默认的本地过渡就够了。只有当嵌套的 {#if} 导致父块销毁时子元素没有过渡,才需要考虑 |global

过渡事件

in:out: 同样会触发过渡事件,跟 transition: 一致。

  • onintrostart:进入过渡开始
  • onintroend:进入过渡结束
  • onoutrostart:离开过渡开始
  • onoutroend:离开过渡结束
<script>
	import { fly, fade } from 'svelte/transition';

	let visible = $state(false);
	let status = $state('');
</script>

{#if visible}
	<div
		in:fly={{ y: 100 }}
		out:fade
		onintrostart={() => status = '进入开始'}
		onintroend={() => status = '进入完成'}
		onoutrostart={() => status = '离开开始'}
		onoutroend={() => status = '离开完成'}
	>
		{status}
	</div>
{/if}

<button onclick={() => visible = !visible}>切换</button>

实战:交错过渡

利用 delay 参数可以实现交错出场效果——多个元素依次出现。

<script>
	import { fly } from 'svelte/transition';

	let items = ['苹果', '香蕉', '橙子', '葡萄', '西瓜'];
	let visible = $state(false);
</script>

<button onclick={() => visible = !visible}>切换</button>

{#if visible}
	{#each items as item, i}
		<div
			in:fly={{ y: 20, delay: i * 100, duration: 400 }}
			out:fly={{ y: -20, delay: (items.length - i - 1) * 100, duration: 400 }}
			style="padding: 8px; margin: 4px 0; background: #f0f0f0;"
		>
			{item}
		</div>
	{/each}
{/if}

进入时每个元素延迟 i * 100 毫秒出场,离开时反过来——最后一个先消失,制造出波浪般的效果。

本节回顾

  • in:out: 分别控制进入和离开动画,可以设置不同效果
  • transition: 不同,in:/out: 不会中途逆转,被打断后从头开始
  • 自定义过渡函数的第三个参数包含 direction,可据此返回不同配置
  • 默认是本地过渡,加 |global 修饰符可让父块变化时也触发
  • 利用 delay 参数可以实现交错出场效果
  • 过渡事件(introstart/introend/outrostart/outroend)同样适用