Svelte 5项目登录登出实现及数据实时更新问题求助
问题描述
我正在开发一个校园网站前端,用户无需注册,仅支持登录/登出操作。目前登录页面已开发完成,但存在两个问题:
- 用户数据无法实时更新,首页必须刷新才能获取最新用户信息;
- 不知道如何实现按钮触发的登出功能。
现有实现代码
login/+page.server.js
import { createSession, getUser } from '$lib/fetchData.svelte.js'; import { redirect } from '@sveltejs/kit'; export const actions = { default: async (event) => { const data = await event.request.formData(); const user = getUser({ firstName: data.get('firstName'), lastName: data.get('lastName'), year: data.get('year'), section: data.get('section') }) event.cookies.set('sessionId', createSession(user), { path: '/'}); redirect(302, '/'); return { success: true } } }
login/+page.svelte
<script> import { Button } from "$lib/components/ui/button"; import * as Card from "$lib/components/ui/card"; import { Input } from "$lib/components/ui/input"; import { Label } from "$lib/components/ui/label"; import * as Select from "$lib/components/ui/select"; import { Checkbox } from "$lib/components/ui/checkbox"; import { getContext, setContext } from "svelte"; import { goto } from "$app/navigation"; import { applyAction, enhance } from '$app/forms'; let { data, form } = $props(); let year = $state(1); let section = $state('A'); let sections = $derived(generateAlphabetArray(getSections(year))); let teacher = $state(false); function generateAlphabetArray(length) { const alphabet = 'ABCDEFGHILMNOPQRSTUVWXYZ'; return Array.from({ length }, (_, i) => alphabet[i % alphabet.length]); } function getSections(classe) { const classes = [ { classe: 1, sezioni: 12 }, { classe: 2, sezioni: 11 }, { classe: 3, sezioni: 12 }, { classe: 4, sezioni: 11 }, { classe: 5, sezioni: 10 } ] return classes.find(c => c.classe === classe).sezioni; } function changeClass(e) { year = e.value; if (!sections.includes(section)) section = sections[0]; } </script> <div class="h-full grid items-center"> <Card.Root class="mx-auto max-w-sm"> <Card.Header> <Card.Title class="text-xl">Accedi</Card.Title> </Card.Header> <Card.Content> <form class="grid gap-4" method="POST" use:enhance={({ formElement, form, action, cancel, submitter }) => { return async ({ result }) => { if (result.type === 'redirect') { goto(result.location); } else { await applyAction(result); } } }} > <div class="grid gap-2"> <Label for="first-name">Nome</Label> <Input id="first-name" placeholder="Mario" name="firstName" required /> </div> <div class="grid gap-2"> <Label for="last-name">Cognome</Label> <Input id="last-name" placeholder="Rossi" name="lastName" required /> </div> <div class="flex gap-2"> <Label for="teacher">Professore</Label> <Checkbox bind:checked={teacher} id="teacher" name="teacher"/> </div> {#if !teacher} <div class="grid grid-cols-2 gap-4"> <div class="grid gap-2"> <Label for="year">Classe</Label> <Select.Root name="year" id="year" selected={{label: '1', value: year}} onSelectedChange={changeClass} > <Select.Trigger class="w-full"> <Select.Value placeholder="1"/> </Select.Trigger> <Select.Content> {#each {length: 5} as _, i} <Select.Item value={i + 1}>{i + 1}</Select.Item> {/each} </Select.Content> </Select.Root> </div> <div class="grid gap-2"> <Label for="section">Sezione</Label> <Select.Root name="section" id="section" selected={{label: section, value: section}} onSelectedChange={(e) => section = e.value} > <Select.Trigger class="w-full"> <Select.Value placeholder="A"/> </Select.Trigger> <Select.Content> {#each sections as letter} <Select.Item value={letter} class="text-center">{letter}</Select.Item> {/each} </Select.Content> </Select.Root> </div> </div> {/if} <Button type="submit" class="w-full" > Accedi </Button> </form> <div class="mt-4 text-center text-sm"> Se non riesci ad accedere manda una mail all'indirizzo <p class="underline"> dynamo.studenti@gmail.com </p> </div> </Card.Content> </Card.Root> </div>
/+layout.server.js
export const load = async (event) => { return { user: event.locals.user } }
/+hooks.server.js
import { getUserFromSession } from '$lib/fetchData.svelte'; export const handle = async ({ event, resolve }) => { event.locals.user = await getUserFromSession(event.cookies.get('sessionId')); return resolve(event); }
/+layout.svelte
<script> import { setContext } from 'svelte'; import '../app.css'; let { children, data } = $props(); setContext('user', data.user); </script> <main class="container flex flex-col gap-2 py-4 h-screen p-2 sm:p-4 overflow-hidden"> {@render children()} </main>
问题解决方案
1. 修复登录后用户数据不实时更新问题
当前登录后手动调用goto跳转,不会自动刷新布局数据,导致data.user仍为旧值。可通过两种方式解决:
方式一:使用默认enhance行为
SvelteKit的enhance默认会在表单提交后自动更新页面数据,移除自定义逻辑即可:
<form class="grid gap-4" method="POST" use:enhance >
方式二:跳转前刷新所有数据
如果需要保留自定义逻辑,在goto前调用invalidateAll强制刷新数据:
<script> // 新增导入 import { invalidateAll } from '$app/navigation'; // ...其他代码 </script> <form class="grid gap-4" method="POST" use:enhance={({ formElement, form, action, cancel, submitter }) => { return async ({ result }) => { if (result.type === 'redirect') { await invalidateAll(); goto(result.location); } else { await applyAction(result); } } }} >
2. 实现登出功能
步骤1:添加服务器端登出逻辑
在根目录创建+page.server.js,添加登出动作:
import { redirect } from '@sveltejs/kit'; export const actions = { logout: async (event) => { // 清除sessionId cookie event.cookies.set('sessionId', '', { path: '/', expires: new Date(0) }); redirect(302, '/'); } }
步骤2:添加登出按钮
在需要显示登出按钮的组件(如导航栏)中添加表单:
<script> import { Button } from "$lib/components/ui/button"; import { enhance } from '$app/forms'; </script> <form method="POST" action="?/logout" use:enhance> <Button type="submit">登出</Button> </form>
enhance会自动处理表单提交并刷新页面数据,确保登出后用户信息实时清除。
内容的提问来源于stack exchange,提问作者mattia
相关产品推荐
相关产品推荐

