阅读(1978) (0)

Svelte 自定义 CSS 过渡

2023-02-22 11:44:23 更新

svelte/transition 模块含有一些内置的过渡效果,但是创建自己的过渡效果也是非常容易,举例来说,这是 fade过渡的代码实现:

function fade(node, {
	delay = 0,
	duration = 400
}) {
	const o = +getComputedStyle(node).opacity;

	return {
		delay,
		duration,
		css: t => `opacity: ${t * o}`
	};
}

该函数接收两个参数(过渡应用到节点以及传入的任何参数)并返回一个过渡对象,该对象可以具有以下属性:

  • delay : 过渡开始(毫秒)。
  • duration: 过渡时长(毫秒)。
  • easingp => t easing 函数)
  • css(t, u) => css函数, where u === 1 - t
  • tick — a (t, u) => {...} 对节点有一定影响的函数。

该 t 值为 0时表示开始,值为1 表示结束,根据情况含义可以截然相反。

大多数情况下,您应该返回该 css 而不是tick 属性,因为 CSS animations 会运行在主线程中,以避免出现混淆。.Svelte '模拟(simulates)' 过渡效果并创建CSS animation,然后使其运行。

例如,fade 过渡会生成 CSS animation ,如下所示:

0% { opacity: 0 }
10% { opacity: 0.1 }
20% { opacity: 0.2 }
/* ... */
100% { opacity: 1 }

不过我们可以发挥更大的创新,做出真正定制化的东西:

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

	let visible = true;

	function spin(node, { duration }) {
		return {
			duration,
			css: t => {
				const eased = elasticOut(t);

				return `
					transform: scale(${eased}) rotate(${eased * 1080}deg);
					color: hsl(
						${~~(t * 360)},
						${Math.min(100, 1000 - 1000 * t)}%,
						${Math.min(50, 500 - 500 * t)}%
					);`
			}
		};
	}
</script>

记住:能力越大责任越大。

示例代码

  • App.svelte

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

	let visible = true;

	function spin(node, { duration }) {
		return {
			duration,
			css: t => {
				const eased = elasticOut(t);

				return `
					transform: scale(${eased}) rotate(${eased * 1080}deg);
					color: hsl(
						${~~(t * 360)},
						${Math.min(100, 1000 - 1000 * t)}%,
						${Math.min(50, 500 - 500 * t)}%
					);`
			}
		};
	}
</script>

<style>
	.centered {
		position: absolute;
		left: 50%;
		top: 50%;
		transform: translate(-50%,-50%);
	}

	span {
		position: absolute;
		transform: translate(-50%,-50%);
		font-size: 4em;
	}
</style>

<label>
	<input type="checkbox" bind:checked={visible}>
	visible
</label>

{#if visible}
	<div class="centered" in:spin="{{duration: 8000}}" out:fade>
		<span>transitions!</span>
	</div>
{/if}