在 shadcn svelte svelte 5 端口中 选择组件(使用 bitsui select)bind:value 要求状态(字符串),但 Writable 也可以工作,所以 bind:value={$theme 或 $language } 正确获取和设置值。但是我的设置组件与作为道具传递给它的附加设置一起使用,并将存储作为对象的元素之一,并且我很难从对象中正确地进行可写工作。
<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 反应式功能的新手,所以也许我要求一些简单的修复。对此深表歉意(
$
语法一起使用,但这里的情况并非如此,因为存储来自
#each
块。您可以将
#each
的内容提取到新组件,将存储传递给该组件,然后它将满足那里的必要条件。但一般来说,我根本不建议在 Svelte 5 中使用存储,除非它是第三方依赖项,但即使如此,您也可以使用 辅助函数将存储转换为状态对象。这在这里也应该是可能的。 一个简化的例子:
<script>
import { writable, derived, fromStore } from 'svelte/store';
const value = writable(2);
const double = derived(value, v => v * 2);
const settings = [
{ name: 'Original', store: value },
{ name: 'Doubled', store: double },
];
</script>
{#each settings as { name, store }}
{@const state = fromStore(store)}
<label>
{name}
{#if 'set' in store}
<input type=number bind:value={state.current} />
{:else}
{state.current}
{/if}
</label> <br>
{/each}
Stores: {$value} * 2 = {$double}