英文:
Sveltekit: different in|out FLY transition (vertical and horizontal) based on screen width
问题
我正在学习Sveltekit,并试图弄清楚如何根据屏幕宽度(例如移动设备和显示器)来实现两种不同方向的进入/退出动画。
类似以下的方式:
如果在显示器屏幕上(最小宽度:640px),则从左侧进入
否则(如果在移动手机上),则从顶部进入
这是我目前的代码示例:
<script lang="ts">
	import { fade, fly } from 'svelte/transition';
	/* 导航菜单 */
	const navigation = [
		{
			title: '主页',
			href: '/'
		},
		{
			title: '关于',
			href: '/about'
		},
		{
			title: '项目',
			href: '/projects'
		},
		{
			title: '联系',
			href: '/contact'
		}
	];
</script>
<nav class="navigation" in:fade={{ duration: 100 }} out:fade={{ duration: 100 }}>
	<ul
		class="navigation__content"
		in:fly={{ x: -1000, duration: 300 }}
		out:fly={{ x: -1000, duration: 300 }}
	>
		{#each navigation as navItem}
			<li class="navigation__page">
				<a href={navItem.href}>{navItem.title}</a>
			</li>
		{/each}
	</ul>
</nav>
我不太确定如何实现这样的效果,我考虑使用#if语句。我在网上搜索了一下,但没有找到有用的信息。
英文:
I'm learning Sveltekit and i am trying to figure out how i can implent two differently oriented in:fly/out:fly based on the width of the screen (mobile and monitor for example).
Something like:
IF on monitor screen (min-width: 640px) then in:fly from the left
ELSE (if on mobile phone) in:fly from the top
This is an example of my code at the moment:
<script lang="ts">
	import { fade, fly } from 'svelte/transition';
	/* Navigation menu */
	const navigation = [
		{
			title: 'Home',
			href: '/'
		},
		{
			title: 'About',
			href: '/about'
		},
		{
			title: 'Projects',
			href: '/projects'
		},
		{
			title: 'Contact',
			href: '/contact'
		}
	];
</script>
<nav class="navigation" in:fade={{ duration: 100 }} out:fade={{ duration: 100 }}>
	<ul
		class="navigation__content"
		in:fly={{ x: -1000, duration: 300 }}
		out:fly={{ x: -1000, duration: 300 }}
	>
		{#each navigation as navItem}
			<li class="navigation__page">
				<a href={navItem.href}>{navItem.title}</a>
			</li>
		{/each}
	</ul>
</nav>
I am not quite sure how i could implement something like this, i was thinking about a #if statement.
I searched the web but couldn't find anything useful.
答案1
得分: 2
你可以创建一个存储,以编程方式匹配媒体查询并相应地切换过渡参数,例如:
```js
import { onMount } from 'svelte';
import { writable } from 'svelte/store';
export function mediaQueryStore(query) {
    const store = writable(false);
    onMount(() => {
        const mediaQueryList = window.matchMedia(query);
        const onChange = () => store.set(mediaQueryList.matches);
        mediaQueryList.addEventListener('change', onChange);
        onChange();
        return () => mediaQueryList.removeEventListener('change', onChange);
    });
    return { subscribe: store.subscribe };
}
const small = mediaQueryStore('(max-width: 600px)');
<div transition:fly={$small ?
  { x: -1000, duration: 300 } : 
  { y: -1000, duration: 300 }}>
(如果进出动画相同,你可以只使用 transition:...)
<details>
<summary>英文:</summary>
You can create a store that programmatically matches a media query and switch out the transition arguments accordingly, e.g.
```js
import { onMount } from 'svelte';
import { writable } from 'svelte/store';
export function mediaQueryStore(query) {
	const store = writable(false);
	
	onMount(() => {
		const mediaQueryList = window.matchMedia(query);
		const onChange = () => store.set(mediaQueryList.matches);
		mediaQueryList.addEventListener('change', onChange);
		onChange();
		return () => mediaQueryList.removeEventListener('change', onChange);
	});
	return { subscribe: store.subscribe };
}
const small = mediaQueryStore('(max-width: 600px)');
<div transition:fly={$small ?
  { x: -1000, duration: 300 } : 
  { y: -1000, duration: 300 }}>
(If in/out animations are the same, you can just use transition:...)
答案2
得分: 2
一种方法是通过内部宽度绑定(教程链接)来监视窗口宽度,并相应地设置 x 和 y。
<script>
	import {fly} from 'svelte/transition';
	let innerWidth;
	const threshold = 640;
	$: x = innerWidth >= threshold ? -100 : 0;
	$: y = innerWidth < threshold ? -100 : 0;
	let nrs = [0,1,2,3,4,5,6,7];
	function add() {
		nrs = [...nrs, nrs.length];
	}
</script>
<svelte:window bind:innerWidth />
<div id="page">
	<button on:click={add}>add one</button>
	<button on:click={() => nrs = [0,1,2,3]}>reset</button>
	innerWidth: {innerWidth}
	<div id="nrs">
		{#each nrs as nr (nr)}
		<div class="nr"
			 in:fly="{{x, y}}"
			 >
			{nr}
		</div>
		{/each}
	</div>
</div>
<style>
	#page {
		width: 100%;
		height: 100%;
		padding: 2rem;
		background: lightgrey;
	}
	#nrs {
		display: flex;
		align-items: flex-start;
		flex-wrap: wrap;
		gap: .5rem;
	}
	.nr {
		width: 4rem;
		height: 4rem;
		display: grid;
		place-content: center;
		background: black;
		color: white;
	}
	:global(body) {
		padding: 0;
	}
	:global(*) {
		box-sizing: border-box;
	}
</style>
英文:
One way would be to watch the window width via the innerWidth binding (tutorial) and set x and y accordingly
<script>
import {fly} from 'svelte/transition'
let innerWidth
const threshold = 640
$: x = innerWidth >= threshold ? -100 : 0
$: y = innerWidth < threshold ? -100 : 0
let nrs = [0,1,2,3,4,5,6,7]
function add() {
nrs = [...nrs, nrs.length] 
}
</script>
<svelte:window bind:innerWidth />
<div id="page">
<button on:click={add}>add one</button>
<button on:click={() => nrs = [0,1,2,3]}>reset</button>
innerWidth: {innerWidth}
<div id="nrs">
{#each nrs as nr (nr)}
<div class="nr"
in:fly="{{x, y}}"
>
{nr}
</div>
{/each}
</div>
</div>
<style>
#page {
width: 100%;
height: 100%;
padding: 2rem;
background: lightgrey;
}
#nrs {
display: flex;
align-items: flex-start;
flex-wrap: wrap;
gap: .5rem;
}
.nr {
width: 4rem;
height: 4rem;
display: grid;
place-content: center;
background: black;
color: white;
}
:global(body) {
padding: 0;
}
:global(*) {
box-sizing: border-box;
}
</style>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论