在 Svelte 5 中,我如何用标签包裹每个子项,如下例所示?
{#if children}
{#each children as child}
<button
onclick={() => {
handleClick();
}}
>
{@render child?.()}
</button>
{/each}
{/if}
在 Svelte 5 中,我如何用标签包裹每个子项,如下例所示?
{#if children}
{#each children as child}
<button
onclick={() => {
handleClick();
}}
>
{@render child?.()}
</button>
{/each}
{/if}
在我的 Svelte 4 应用中,我动态加载了组件,所有组件都有不同的 props。非常简单的复制(也可在Svelte Playground上使用):
// App.svelte
<script lang="ts">
import One from "./One.svelte";
import Two from "./Two.svelte";
import type { ComponentType } from "svelte";
type Item = {
component: ComponentType;
};
const items: Item[] = [
{ component: One, one: "World" },
{ component: Two, two: "Svelte" },
];
</script>
<div class="container py-20 text-white">
{#each items as item}
<div>
<svelte:component this={item.component} {...item} />
</div>
{/each}
</div>
// One.svelte
<script lang="ts">
export let one;
</script>
Hello {one}
// Two.svelte
<script lang="ts">
export let two;
</script>
Goodbye {two}
运行良好,没有任何警告或错误,到目前为止没有任何投诉。但是我想迁移到 Svelte 5,现在我收到一堆 TypeScript 错误。例如ComponentType
已弃用,以及类似以下内容:
Type '__sveltets_2_IsomorphicComponent<{ one: any; }, { [evt: string]: CustomEvent<any>; }, {}, {}, string>' is not assignable to type 'ComponentType'.
Type '__sveltets_2_IsomorphicComponent<{ one: any; }, { [evt: string]: CustomEvent<any>; }, {}, {}, string>' is not assignable to type 'new (options: ComponentConstructorOptions<Record<string, any>>) => SvelteComponent<Record<string, any>, any, any>'.
Types of parameters 'options' and 'options' are incompatible.
Type 'ComponentConstructorOptions<Record<string, any>>' is not assignable to type 'ComponentConstructorOptions<{ one: any; }>'.
Property 'one' is missing in type 'Record<string, any>' but required in type '{ one: any; }'.
我该如何重构代码,使其继续工作,而不会出现 TypeScript 错误,并且不必对每个组件进行强类型化?在我的实际应用中,涉及许多组件,每个组件都有一大堆不同的 props。我不想为每个组件创建类型别名。
只需更改ComponentType
为Component
即可消除弃用警告,但其他警告基本仍然相同:
Type '__sveltets_2_IsomorphicComponent<{ one: any; }, { [evt: string]: CustomEvent<any>; }, {}, {}, string>' is not assignable to type 'Component<{}, {}, string>'.
Types of parameters 'props' and 'props' are incompatible.
Type '{}' is not assignable to type '{ one: any; } & { $$events?: { [evt: string]: CustomEvent<any>; } | undefined; $$slots?: {} | undefined; }'.
Property 'one' is missing in type '{}' but required in type '{ one: any; }'.ts(2322)
更改ComponentType
为SvelteComponent
也不会让事情变得更好。当我使用该unknown
类型时,我收到此警告:
Argument of type 'unknown' is not assignable to parameter of type 'ConstructorOfATypedSvelteComponent | Component<any, any, any> | null | undefined'.
至少那只是一个警告,而不是数组中的一大堆,所以更好,但这真的不能用更好的方法解决吗(无需输入每个组件)?
我正在尝试在 Svelte 5 中实现表单提交操作,但似乎遇到了一些反应性问题。
<script>
const formData = $state({
name: 'abc',
})
const saveData = (e) => {
e.preventDefault()
console.log(formData)
}
</script>
<form onsubmit={saveData}>
<input type="text" bind:value={formData.name}/>
<button type="submit">
Create
</button>
</form>
<pre>
{formData.name}
</pre>
正如预期的那样,{formData.name}
显示正确的值,但无论我在表单中输入什么,console.log(formData)
始终都会输出。我如何在提交处理程序中检索最新的值?abc
我如何在 svelte 中添加这个 buymecoffee 脚本标签。
type="text/javascript"
src="https://cdnjs.buymeacoffee.com/1.0.0/button.prod.min.js"
data-name="bmc-button"
data-slug="slug_name"
data-color="#FFDD00"
data-emoji="☕"
data-font="Lato"
data-text="Buy me a coffee"
data-outline-color="#000000"
data-font-color="#000000"
data-coffee-color="#ffffff"
></script>;
我的页面中已经有另一个脚本标签,如下所示:
<script lang='ts'>
import { onMount } from 'svelte';
let sectionsVisible = [false, false, false, false];
function handleScroll() {
const sections = document.querySelectorAll('section');
sections.forEach((section, index) => {
const rect = section.getBoundingClientRect();
if (rect.top < window.innerHeight * 0.75) {
sectionsVisible[index] = true;
}
});
}
onMount(() => {
handleScroll();
window.addEventListener('scroll', handleScroll);
});
</script>
我如何才能将这两个脚本标签合并到一个页面中。是否可以将 buymecoffee 按钮放置在我想要的位置?
我尝试在 Svelte 5 应用程序中使用 page.js 进行客户端路由,但遇到了一个奇怪的现象:当我将路由逻辑放在App.svelte
组件内时,一切都正常:
<!-- App.svelte -->
<script lang="ts">
import router from "page"
import Index from "./pages/index.svelte"
import About from "./pages/about.svelte"
import NotFound from "./pages/404.svelte"
let Page = $state(Index)
router("/", () => Page = Index)
router("/about", () => Page = About)
router("*", () => Page = NotFound)
router.start()
</script>
<Page/>
但是,当我尝试将此逻辑提取到外部模块时,路由就会失败,并且到其他页面的链接不会执行任何操作:
// router.svelte.ts
import router from "page"
import Index from "../pages/index.svelte"
import About from "../pages/about.svelte"
import NotFound from "../pages/404.svelte"
let page = $state(Index);
export const createRouter = () => {
const registerRoutes = () => {
router("/", () => page = Index)
router("/about", () => page = About)
router("*", () => page = NotFound)
router.start()
}
return {
get page() {
return page
},
registerRoutes,
}
}
现在,当我从我的 App.svelte 文件调用此路由器时,页面最初可以正确加载,但页面之间的链接不再起作用:
<!-- App.svelte -->
<script lang="ts">
import {createRouter} from "./router.svelte";
const router = createRouter()
router.registerRoutes()
let Page = router.page
</script>
<Page/>
我认为我对所涉及的反应性存在误解,但也许有人可以给我指明正确的方向。
在svelte 5 的 shadcn ui 端口中-选择组件(使用bitsui select)bind:value 要求 state(string),但 Writable<string> 也同样有效,因此 bind:value={$theme 或 $language} 可以正确获取和设置值。但我的设置组件可以使用作为 props 传递给它的附加设置,并将 store 作为对象元素之一,我无法从对象中正确获取 writable 工作。
<script lang="ts" module>
interface SelectItem {
label: string;
labelRu: string;
value: string;
}
export interface Setting {
store: Writable<string>;
name: string;
nameRu: string;
values: SelectItem[];
}
</script>
<script lang="ts">
import * as Select from '$shared/components/ui/select/index.js';
import { theme } from '$shared/stores/theme';
import { language } from '$shared/stores/language';
import { derived, type Writable } from 'svelte/store';
let { additionalSettings = null }: { additionalSettings?: { [key: string]: Setting } | null } =
$props();
let clazz = $state('');
export { clazz as class };
let settings: { [key: string]: Setting } = {
theme: {
store: theme,
name: 'Theme',
nameRu: 'Тема',
values: [
{ label: 'Light', labelRu: 'Светлая', value: 'light' },
{ label: 'Dark', labelRu: 'Темная', value: 'dark' }
]
},
language: {
store: language,
name: 'Lingo',
nameRu: 'Язык',
values: [
{ label: 'English', labelRu: 'Английский', value: 'en' },
{ label: 'Russian', labelRu: 'Русский', value: 'ru' }
]
}
};
settings = { ...settings, ...(additionalSettings ?? {}) };
const settingLabel = Object.fromEntries(
Object.entries(settings).map(([key, setting]) => [
key,
derived([setting.store, language], ([$store, $language]) => {
const selectedValue = setting.values.find((value) => value.value === $store);
return $language === 'ru' ? selectedValue?.labelRu : selectedValue?.label;
})
])
);
</script>
<div
class="{clazz !== '' ? clazz + ' ' : ''}flex min-w-[240px] flex-col space-y-4 px-2 py-4 text-sm"
>
{#each Object.entries(settings) as [key, setting]}
<div class="flex items-center space-x-2">
<p class="min-w-[48px]">{$language === 'ru' ? setting.nameRu : setting.name}:</p>
<Select.Root type="single" name={key} bind:value={$setting.store}>
<Select.Trigger>
{#await settingLabel[key] then label}
{(label ?? $language === 'ru')
? 'Выберите ' + setting.nameRu
: 'Select ' + setting.name}
{/await}
</Select.Trigger>
<Select.Content>
{#each setting.values as value}
<Select.Item value={value.value}>
{$language === 'ru' ? value.labelRu : value.label}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
{/each}
</div>
我是 Svelte 5 反应功能的新手,所以也许我问的是一些容易修复的问题。对此抱歉(
我有一个<MyInput />
像这样的自定义组件:
<script lang="ts">
//=== MyInput.svelte ===
type Props = {
input: HTMLInputElement
value: string
}
let { input = $bindable(), value = $bindable() }: Props = $props()
</script>
<input bind:this={input} bind:value />
我希望能够以编程方式从父组件模糊此字段,无论它在何处使用。
<script lang="ts">
//=== Parent.svelte ===
import MyInput from '$lib/MyInput.svelte'
let input: HTMLInputElement
function blurField(){
input.blur() <!-- console error
}
</script>
<MyInput {input} {value} />
<button onclick={() => blurField()}>Blur Field</button>
我不清楚如何将input
父组件中的引用绑定到实际的子组件。它似乎实际上没有将input
父组件中的引用与子组件的绑定联系起来。
知道我做错了什么吗?
假设我有一个名为的父组件SplitView.svelte
:
<script lang="ts">
import type { Snippet } from 'svelte'
type Props = {
master: Snippet
detail: Snippet
}
let { master, detail }: Props = $props()
</script>
<div class="split">
<div id="master">
{@render master()}
</div>
<div id="detail">
{@render detail()}
</div>
</div>
我在其他地方使用过这样的方法:
<script lang="ts">
import SplitView from '$lib/components/shared/SplitView.svelte'
import Master from './master/PricingMaster.svelte'
import Detail from './detail/PricingDetail.svelte'
</script>
<SplitView master={Master} detail={Detail} /> <-- ESLint error
我在master
和detail
属性上遇到了一个 linter 错误:
Type '__sveltets_2_IsomorphicComponent<Record<string, never>,
{ [evt: string]: CustomEvent<any>; }, {}, {}, string>' is not assignable to type 'Snippet<[]>'.
Target signature provides too few arguments. Expected 2 or more, but got 0.ts(2322)
作为 props 发送的组件是否不是类型Snippet
?我做错了什么?