mcpField
S
svelte-components

svelte-components

github.com/exceptionless开发2.5k43 次安装1 天前更新
代码仓库

关于 svelte-components

面向 Svelte 开发者的组件规范指南,涵盖组件结构、Svelte runes、属性和交互约定,并要求在 UI 开发中检查视觉效果与键盘可访问性。

主要功能

  1. 01组件命名与目录组织
  2. 02Svelte runes 和属性用法
  3. 03shadcn-svelte 组件规范
  4. 04事件与 snippet 模式
  5. 05视觉和键盘可访问性检查

适用场景

  1. 01构建一致的 Svelte 组件
  2. 02检查组件结构与状态管理
  3. 03验证 UI 外观和交互

MCP 相关

该技能指导 UI 开发者使用 Chrome MCP 截取快照或屏幕截图,并检查渲染、交互状态和响应式布局。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/exceptionless/exceptionless --skill svelte-components

安装后在 Claude Code 中输入/svelte-components确认已加载。

详细介绍

Svelte 组件

文档: svelte.dev | 使用 context7 查阅 API 参考

使用 Chrome MCP 进行视觉验证

务必通过 Chrome MCP 对 UI 更改进行视觉验证:

  1. 修改组件后,使用 Chrome MCP 获取快照或截图
  2. 确认组件渲染正确且符合预期设计
  3. 在适用时测试交互状态(悬停、聚焦、禁用)
  4. 检查不同视口尺寸下的响应行为
  5. 默认使用 /next 网站路径进行验证

这一视觉验证流程可以发现自动化测试可能遗漏的样式问题、布局问题和无障碍回归问题。

文件组织

命名约定
  • 所有组件文件均使用 kebab-case:stack-status-badge.svelte、user-profile-card.svelte
  • 与功能切片放在一起,并与 API 控制器保持一致
目录结构
src/lib/features/
├── organizations/           # Matches OrganizationController
│   ├── components/
│   │   ├── organization-card.svelte
│   │   └── organization-switcher.svelte
│   ├── api.svelte.ts
│   ├── models.ts
│   └── schemas.ts
├── stacks/                  # Matches StackController
│   └── components/
│       └── stack-status-badge.svelte
└── shared/                  # Shared across features
    └── components/
        ├── data-table/
        ├── navigation/
        └── typography/

始终使用 shadcn-svelte 组件

按钮、输入框或表单元素不得使用原生 HTML:

<script lang="ts">
    import { Button } from '$comp/ui/button';
    import { Input } from '$comp/ui/input';
    import * as Card from '$comp/ui/card';
</script>


<Card.Root>
    <Card.Header>
        <Card.Title>Settings</Card.Title>
    </Card.Header>
    <Card.Content>
        <Input placeholder="Enter value" />
    </Card.Content>
    <Card.Footer>
        <Button>Save</Button>
    </Card.Footer>
</Card.Root>


<button class="...">Save</button>
<input type="text" />

Runes

$state - 响应式状态
<script lang="ts">
    let count = $state(0);
    let user = $state<User | null>(null);
    let items = $state<string[]>([]);
</script>
$derived - 计算值
<script lang="ts">
    let count = $state(0);
    let doubled = $derived(count * 2);
    let isEven = $derived(count % 2 === 0);

    // Complex derived
    let summary = $derived.by(() => {
        return items.filter(i => i.active).map(i => i.name).join(', ');
    });
</script>
$effect - 副作用
<script lang="ts">
    let searchTerm = $state('');

    $effect(() => {
        console.log('Search term changed:', searchTerm);
        return () => console.log('Cleaning up');
    });
</script>

Props

<script lang="ts">
    interface Props {
        name: string;
        count?: number;
        onUpdate?: (value: number) => void;
        children?: import('svelte').Snippet;
    }

    let { name, count = 0, onUpdate, children }: Props = $props();
</script>

事件处理

使用 onclick,而不是 on:click:

<Button onclick={() => handleClick()}>Click me</Button>
<Input oninput={(e) => (value = e.currentTarget.value)} />

Snippets(内容投影)

使用 snippets 替代 <slot>。示例来自 src/Exceptionless.Web/ClientApp/src/routes/(auth)/login/+page.svelte:

<form.Subscribe selector={(state) => state.errors}>
    {#snippet children(errors)}
        <ErrorMessage message={getFormErrorMessages(errors)}></ErrorMessage>
    {/snippet}
</form.Subscribe>

<form.Field name="email">
    {#snippet children(field)}
        <Field.Field data-invalid={ariaInvalid(field)}>
            <Field.Label for={field.name}>Email</Field.Label>
            <Input
                id={field.name}
                value={field.state.value}
                oninput={(e) => field.handleChange(e.currentTarget.value)}
            />
            <Field.Error errors={mapFieldErrors(field.state.meta.errors)} />
        </Field.Field>
    {/snippet}
</form.Field>

类名合并

使用数组语法设置条件类名:

<div class={['flex items-center', expanded && 'bg-muted', className]}>
    Content
</div>

<Button class={['w-full', isActive && 'bg-primary']}>Save</Button>

键盘无障碍

所有交互组件都必须支持键盘操作:

  • 使用 Button 组件(自动处理焦点)
  • 确保自定义交互包含 tabindex 和键盘事件处理器
  • 使用纯键盘导航进行测试

请参阅 无障碍,了解 WCAG 指南。

导入

<script lang="ts">
    // Use $app/state instead of $app/stores
    import { page } from '$app/state';

    // Access page data
    let currentPath = $derived(page.url.pathname);
</script>

参考资料

评论

支持 Markdown