因为我们使用的是 <form>
,所以即使用户没有 JavaScript(这种情况比你想象的更常见),我们的应用也可以工作。这很好,因为这意味着我们的应用具有弹性。
¥Because we’re using <form>
, our app works even if the user doesn’t have JavaScript (which happens more often than you probably think). That’s great, because it means our app is resilient.
大多数情况下,用户确实有 JavaScript。在这些情况下,我们可以逐步增强体验,就像 SvelteKit 使用客户端路由逐步增强 <a>
元素一样。
¥Most of the time, users do have JavaScript. In those cases, we can progressively enhance the experience, the same way SvelteKit progressively enhances <a>
elements by using client-side routing.
从 $app/forms
导入 enhance
函数...
¥Import the enhance
function from $app/forms
...
<script>
import { enhance } from '$app/forms';
let { data, form } = $props();
</script>
<script lang="ts">
import { enhance } from '$app/forms';
let { data, form } = $props();
</script>
...并将 use:enhance
指令添加到 <form>
元素:
¥...and add the use:enhance
directive to the <form>
elements:
<form method="POST" action="?/create" use:enhance>
<form method="POST" action="?/delete" use:enhance>
这就是全部内容!现在,当启用 JavaScript 时,use:enhance
将模拟浏览器原生行为,但整页重新加载除外。它将:
¥And that’s all it takes! Now, when JavaScript is enabled, use:enhance
will emulate the browser-native behaviour except for the full-page reloads. It will:
更新
form
prop¥update the
form
prop在成功响应时使所有数据无效,导致
load
函数重新运行¥invalidate all data on a successful response, causing
load
functions to re-run在重定向响应中导航到新页面
¥navigate to the new page on a redirect response
如果发生错误,则渲染最近的错误页面
¥render the nearest error page if an error occurs
现在我们正在更新页面而不是重新加载它,我们可以对诸如过渡之类的东西进行一些花哨的操作:
¥Now that we’re updating the page rather than reloading it, we can get fancy with things like transitions:
<script>
import { fly, slide } from 'svelte/transition';
import { enhance } from '$app/forms';
let { data, form } = $props();
</script>
<script lang="ts">
import { fly, slide } from 'svelte/transition';
import { enhance } from '$app/forms';
let { data, form } = $props();
</script>
<li in:fly={{ y: 20 }} out:slide>...</li>
<script>
let { data, form } = $props();
</script>
<div class="centered">
<h1>todos</h1>
{#if form?.error}
<p class="error">{form.error}</p>
{/if}
<form method="POST" action="?/create">
<label>
add a todo:
<input
name="description"
value={form?.description ?? ''}
autocomplete="off"
required
/>
</label>
</form>
<ul class="todos">
{#each data.todos as todo (todo.id)}
<li>
<form method="POST" action="?/delete">
<input type="hidden" name="id" value={todo.id} />
<span>{todo.description}</span>
<button aria-label="Mark as complete"></button>
</form>
</li>
{/each}
</ul>
</div>
<style>
.centered {
max-width: 20em;
margin: 0 auto;
}
label {
width: 100%;
}
input {
flex: 1;
}
span {
flex: 1;
}
button {
border: none;
background: url(./remove.svg) no-repeat 50% 50%;
background-size: 1rem 1rem;
cursor: pointer;
height: 100%;
aspect-ratio: 1;
opacity: 0.5;
transition: opacity 0.2s;
}
button:hover {
opacity: 1;
}
.saving {
opacity: 0.5;
}
</style>