mcpField
F
frontend-development

frontend-development

github.com/samhvw8开发15174 次安装今天更新
代码仓库

关于 frontend-development

这项前端开发指南 Skill 覆盖 React、Vue 3、Svelte 5 和 Angular,帮助开发者选择模式并构建组件、路由、数据获取及类型化应用结构,提供各框架专属指导。

主要功能

  1. 01比较四种前端框架
  2. 02指导组件与功能目录结构
  3. 03涵盖路由和数据获取
  4. 04应用 TypeScript 与性能实践
  5. 05提供框架专属模式

适用场景

  1. 01规划新的前端项目
  2. 02构建组件或应用功能
  3. 03改进数据获取与路由
  4. 04评估框架迁移方案

安装

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

$npx skills add https://github.com/samhvw8/dotfiles --skill frontend-development

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

resources/
common-patterns.md
complete-examples.md
component-patterns.md
data-fetching.md
file-organization.md
loading-and-error-states.md
performance.md
routing-guide.md
styling-guide.md
typescript-standards.md

详细介绍

前端开发指南

目的

这是一份全面的现代前端开发指南,涵盖 React、Vue 3、Svelte 5 和 Angular。内容包括框架专属模式、常见架构原则和跨框架最佳实践。

何时使用此技能

  • 在 React、Vue、Svelte 或 Angular 中创建组件或页面
  • 使用框架专属模式开发新功能
  • 实现状态管理(Pinia、Zustand、stores、signals)
  • 设置路由(TanStack Router、Vue Router、SvelteKit、Angular Router)
  • 使用数据获取模式(TanStack Query、composables、SvelteKit load 函数)
  • 跨框架优化性能
  • 组合和复用组件
  • 集成 TypeScript 并遵循最佳实践
  • 为项目选择合适的框架
  • 在框架之间迁移

框架选择指南

根据项目需求选择框架:

框架最适合学习曲线性能生态系统
React大型应用、强类型、企业级项目中等良好最大
Vue 3渐进式采用、易于上手低优秀不断壮大
Svelte 5小型/中型应用、原生体验低最佳较小
Angular企业级项目、功能全面陡峭良好完备

快速决策:

  • 已有代码库? 使用现有框架,或规划迁移
  • 团队经验? 利用现有知识
  • 项目规模? 大型 → React/Angular,中型 → Vue/React,小型 → Svelte/Vue
  • 性能要求高? Svelte > Vue > React ≈ Angular
  • 需要 TypeScript? 都能很好地支持(Angular 集成最佳)
  • 生态系统需求? React > Vue > Angular > Svelte

详细模式请参阅下方的框架专属章节。


快速比较框架

特性ReactVue 3Svelte 5Angular
响应性Hooks(useState)ref/reactiveRunes($state)Signals
组件JSX/TSXSFC (.vue)SFC (.svelte)Decorators/Class
状态管理Zustand/ContextPiniaStoresServices
路由React Router/TanStackVue RouterSvelteKitAngular Router
数据获取TanStack QueryComposables/VueQueryLoad 函数HttpClient/RxJS
样式CSS-in-JS/ModulesScoped CSSScoped CSS组件样式
全栈Next.jsNuxtSvelteKitUniversal/SSR
包体积~40KB~32KB~3KB~60KB
编译器运行时运行时编译时AOT 编译器

跳转到:


React 开发

新组件检查清单

要创建组件?请遵循此检查清单:

  • 使用带 TypeScript 的 React.FC<Props> 模式
  • 如果组件较重,进行懒加载:React.lazy(() => import())
  • 加载状态使用 <SuspenseLoader> 包裹
  • 使用 useSuspenseQuery 获取数据
  • 导入别名:@/、~types、~components、~features
  • 样式:少于 100 行时内联,超过 100 行时使用单独文件
  • 对传递给子组件的事件处理函数使用 useCallback
  • 在底部添加默认导出
  • 加载指示器不要使用提前返回
  • 使用 useMuiSnackbar 通知用户
新功能检查清单

创建新功能?请按以下结构设置:

  • 创建 features/{feature-name}/ 目录
  • 创建子目录:api/、components/、hooks/、helpers/、types/
  • 创建 API 服务文件:api/{feature}Api.ts
  • 在 types/ 中设置 TypeScript 类型
  • 在 routes/{feature-name}/index.tsx 中创建路由
  • 懒加载功能组件
  • 使用 Suspense 边界
  • 从功能的 index.ts 导出公共 API

导入别名速查

别名解析为示例
@/src/import { apiClient } from '@/lib/apiClient'
~typessrc/typesimport type { User } from '~types/user'
~componentssrc/componentsimport { SuspenseLoader } from '~components/SuspenseLoader'
~featuressrc/featuresimport { authApi } from '~features/auth'

定义于:vite.config.ts 第 180-185 行


常用导入速查表

// React & Lazy Loading
import React, { useState, useCallback, useMemo } from 'react';
const Heavy = React.lazy(() => import('./Heavy'));

// MUI Components
import { Box, Paper, Typography, Button, Grid } from '@mui/material';
import type { SxProps, Theme } from '@mui/material';

// TanStack Query (Suspense)
import { useSuspenseQuery, useQueryClient } from '@tanstack/react-query';

// TanStack Router
import { createFileRoute } from '@tanstack/react-router';

// Project Components
import { SuspenseLoader } from '~components/SuspenseLoader';

// Hooks
import { useAuth } from '@/hooks/useAuth';
import { useMuiSnackbar } from '@/hooks/useMuiSnackbar';

// Types
import type { Post } from '~types/post';

主题指南

🎨 组件模式

现代 React 组件使用:

  • React.FC<Props>,确保类型安全
  • React.lazy(),实现代码拆分
  • SuspenseLoader,处理加载状态
  • 命名常量 + 默认导出模式

核心概念:

  • 懒加载较重的组件(DataGrid、图表、编辑器)
  • 始终将懒加载组件包裹在 Suspense 中
  • 使用 SuspenseLoader 组件(带淡入淡出动画)
  • 组件结构:Props → Hooks → 处理函数 → 渲染 → 导出

📖 完整指南:resources/component-patterns.md


📊 数据获取

主要模式:useSuspenseQuery

  • 与 Suspense 边界配合使用
  • 缓存优先策略(调用 API 前先检查网格缓存)
  • 替代 isLoading 检查
  • 使用泛型确保类型安全

API 服务层:

  • 创建 features/{feature}/api/{feature}Api.ts
  • 使用 apiClient axios 实例
  • 按功能集中管理方法
  • 路由格式:/form/route(而非 /api/form/route)

📖 完整指南:resources/data-fetching.md


📁 文件组织

features/ 与 components/:

  • features/:特定领域(帖子、评论、身份验证)
  • components/:真正可复用的组件(SuspenseLoader、CustomAppBar)

功能子目录:

features/
  my-feature/
    api/          # API service layer
    components/   # Feature components
    hooks/        # Custom hooks
    helpers/      # Utility functions
    types/        # TypeScript types

📖 完整指南:resources/file-organization.md


🎨 样式

内联样式与单独文件:

  • <100 行:内联 const styles: Record<string, SxProps<Theme>>
  • 100 行:单独的 .styles.ts 文件

主要方法:

  • 对 MUI 组件使用 sx 属性
  • 使用 SxProps<Theme> 确保类型安全
  • 访问主题:(theme) => theme.palette.primary.main

MUI v7 Grid:

<Grid size={{ xs: 12, md: 6 }}>  // ✅ v7 syntax
<Grid xs={12} md={6}>             // ❌ Old syntax

📖 完整指南:resources/styling-guide.md


🛣️ 路由

TanStack Router - 基于文件夹:

  • 目录:routes/my-route/index.tsx
  • 懒加载组件
  • 使用 createFileRoute
  • 在 loader 中添加面包屑数据

示例:

import { createFileRoute } from '@tanstack/react-router';
import { lazy } from 'react';

const MyPage = lazy(() => import('@/features/my-feature/components/MyPage'));

export const Route = createFileRoute('/my-route/')({
    component: MyPage,
    loader: () => ({ crumb: 'My Route' }),
});

📖 完整指南:resources/routing-guide.md


⏳ 加载与错误状态

关键规则:不要提前返回

// ❌ NEVER - Causes layout shift
if (isLoading) {
    return <LoadingSpinner />;
}

// ✅ ALWAYS - Consistent layout
<SuspenseLoader>
    <Content />
</SuspenseLoader>

**原因:**可防止累积布局偏移(CLS),改善用户体验

错误处理:

  • 使用 useMuiSnackbar 向用户反馈
  • 切勿使用 react-toastify
  • 使用 TanStack Query 的 onError 回调

📖 完整指南:resources/loading-and-error-states.md


⚡ 性能

优化模式:

  • useMemo:开销较大的计算(筛选、排序、映射)
  • useCallback:传递给子组件的事件处理函数
  • React.memo:开销较大的组件
  • 防抖搜索(300-500ms)
  • 防止内存泄漏(在 useEffect 中清理)

📖 完整指南:resources/performance.md


📘 TypeScript

规范:

  • 严格模式,不使用 any 类型
  • 函数显式声明返回类型
  • 类型导入:import type { User } from '~types/user'
  • 组件属性接口需包含 JSDoc

📖 完整指南:resources/typescript-standards.md


🔧 常见模式

涵盖主题:

  • 使用 Zod 验证的 React Hook Form
  • DataGrid 包装器契约
  • 对话框组件规范
  • 用于获取当前用户的 useAuth hook
  • 带缓存失效的 mutation 模式

📖 完整指南:resources/common-patterns.md


📚 完整示例

完整可运行示例:

  • 涵盖所有模式的现代组件
  • 完整的功能结构
  • API 服务层
  • 带延迟加载的路由
  • Suspense + useSuspenseQuery
  • 带验证的表单

📖 完整指南:resources/complete-examples.md


React 专属导航指南

需求阅读此资源
创建 React 组件component-patterns.md
使用 TanStack Query 获取数据data-fetching.md
整理文件/文件夹file-organization.md
使用 MUI v7 设置样式styling-guide.md
设置 TanStack Routerrouting-guide.md
处理加载/错误状态loading-and-error-states.md
优化 React 性能performance.md
TypeScript 类型typescript-standards.md
表单/身份验证/DataGridcommon-patterns.md
查看完整 React 示例complete-examples.md

**注意:**以上资源专为 React 编写。有关 Vue/Svelte/Angular,请参阅本文档中的框架章节。


核心原则(适用于所有框架)

  1. 延迟加载大型组件:路由、数据网格、图表、编辑器、模态框
  2. 统一加载状态:通过恰当的加载 UI 避免布局偏移
  3. 类型安全:所有组件和 API 均使用 TypeScript
  4. 组件组合:采用规模小、专注且职责明确的组件
  5. 单向数据流:属性向下传递,事件向上传递
  6. 性能优先:对开销较大的计算进行记忆化,为列表使用虚拟滚动
  7. 功能组织有序:将相关代码分组(组件、状态、类型、工具)
  8. 遵循框架惯用模式:使用特定框架的模式(hooks、composables、runes、服务)
React 专属原则
  1. useSuspenseQuery:新代码的首选数据获取模式
  2. 不使用提前返回:避免布局偏移(使用 Suspense 边界)
  3. 导入别名:使用 @/、~types、~components、~features
  4. 根据规模选择样式:<100 行内编写,>100 行拆分到单独文件
Vue 专属原则
  1. Composition API:优先于 Options API,以便复用
  2. Script Setup:使用它以获得更简洁的语法和更好的性能
  3. Composables:像 React hooks 一样提取可复用逻辑
  4. 使用 Pinia 管理状态:支持 TypeScript 的现代 Vuex 替代方案
Svelte 专属原则
  1. 使用 Runes 实现响应性:使用 $state、$derived、$effect(Svelte 5+)
  2. 使用 SvelteKit 构建应用:利用基于文件的路由和服务端函数
  3. 尽量少用 Stores:Runes 可减少组件对 Stores 的需求
  4. 渐进增强:支持无 JS 运行,并通过 JS 增强
Angular 专属原则
  1. 独立组件:自 v17 起为默认方式(避免使用 NgModules)
  2. 使用 Signals 管理状态:简单的响应式场景优先于 RxJS
  3. OnPush 检测:优化变更检测
  4. 依赖注入:使用 inject() 实现现代 DI

快速参考:文件结构

src/
  features/
    my-feature/
      api/
        myFeatureApi.ts       # API service
      components/
        MyFeature.tsx         # Main component
        SubComponent.tsx      # Related components
      hooks/
        useMyFeature.ts       # Custom hooks
        useSuspenseMyFeature.ts  # Suspense hooks
      helpers/
        myFeatureHelpers.ts   # Utilities
      types/
        index.ts              # TypeScript types
      index.ts                # Public exports

  components/
    SuspenseLoader/
      SuspenseLoader.tsx      # Reusable loader
    CustomAppBar/
      CustomAppBar.tsx        # Reusable app bar

  routes/
    my-route/
      index.tsx               # Route component
      create/
        index.tsx             # Nested route

现代组件模板(快速复制)

import React, { useState, useCallback } from 'react';
import { Box, Paper } from '@mui/material';
import { useSuspenseQuery } from '@tanstack/react-query';
import { featureApi } from '../api/featureApi';
import type { FeatureData } from '~types/feature';

interface MyComponentProps {
    id: number;
    onAction?: () => void;
}

export const MyComponent: React.FC<MyComponentProps> = ({ id, onAction }) => {
    const [state, setState] = useState<string>('');

    const { data } = useSuspenseQuery({
        queryKey: ['feature', id],
        queryFn: () => featureApi.getFeature(id),
    });

    const handleAction = useCallback(() => {
        setState('updated');
        onAction?.();
    }, [onAction]);

    return (
        <Box sx={{ p: 2 }}>
            <Paper sx={{ p: 3 }}>
                {/* Content */}
            </Paper>
        </Box>
    );
};

export default MyComponent;

完整示例请参阅 resources/complete-examples.md


Vue 3 开发

组件模式

组合式 API - 使用 <script setup> 的现代 Vue 3 方法:

<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import type { User } from '@/types/user'

interface Props {
  userId: number
}

const props = defineProps<Props>()
const emit = defineEmits<{
  update: [user: User]
}>()

const user = ref<User | null>(null)
const isLoading = ref(true)
const displayName = computed(() => user.value?.name ?? 'Unknown')

onMounted(async () => {
  user.value = await fetchUser(props.userId)
  isLoading.value = false
})

function handleUpdate() {
  if (user.value) emit('update', user.value)
}
</script>

<template>
  <div class="user-profile">
    <div v-if="isLoading">Loading...</div>
    <div v-else>
      <h2>{{ displayName }}</h2>
      <button @click="handleUpdate">Update</button>
    </div>
  </div>
</template>

<style scoped>
.user-profile {
  padding: 1rem;
}
</style>

关键模式:

  • <script setup> - 简洁的组合式 API 语法
  • defineProps<T>() - 使用泛型实现类型安全的 props
  • defineEmits<T>() - 类型安全的事件
  • ref()、reactive() - 响应式基础 API
  • computed() - 派生状态
  • watch()、watchEffect() - 副作用
  • onMounted、onUnmounted - 生命周期钩子
状态管理(Pinia)
// stores/userStore.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useUserStore = defineStore('user', () => {
  // State
  const users = ref<User[]>([])
  const currentUser = ref<User | null>(null)

  // Getters
  const userCount = computed(() => users.value.length)
  const isAuthenticated = computed(() => currentUser.value !== null)

  // Actions
  async function fetchUsers() {
    users.value = await api.getUsers()
  }

  function setCurrentUser(user: User) {
    currentUser.value = user
  }

  return { users, currentUser, userCount, isAuthenticated, fetchUsers, setCurrentUser }
})

// Component usage
<script setup lang="ts">
import { useUserStore } from '@/stores/userStore'
const userStore = useUserStore()
</script>
路由(Vue Router)
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/',
      component: () => import('@/views/HomeView.vue')
    },
    {
      path: '/users/:id',
      component: () => import('@/views/UserView.vue'),
      props: true
    }
  ]
})

// Component with route params
<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router'

const route = useRoute()
const router = useRouter()
const userId = route.params.id

function goBack() {
  router.push('/')
}
</script>
数据获取模式

组合式函数 - 可复用逻辑:

// composables/useUser.ts
import { ref, type Ref } from 'vue'

export function useUser(id: Ref<number>) {
  const user = ref<User | null>(null)
  const loading = ref(false)
  const error = ref<Error | null>(null)

  async function fetchUser() {
    loading.value = true
    try {
      user.value = await api.getUser(id.value)
    } catch (e) {
      error.value = e as Error
    } finally {
      loading.value = false
    }
  }

  watchEffect(() => {
    fetchUser()
  })

  return { user, loading, error, refetch: fetchUser }
}

// Usage in component
<script setup lang="ts">
const props = defineProps<{ userId: number }>()
const { user, loading, error } = useUser(toRef(props, 'userId'))
</script>

Nuxt.js 服务端:

<script setup lang="ts">
// Nuxt auto-imports composables
const { data: user, pending, error } = await useFetch(`/api/users/${route.params.id}`)
</script>
Vue 3 最佳实践
  • 优先使用组合式 API,而非选项式 API - 更好地支持 TypeScript,且可复用性更强
  • Script setup - 减少样板代码,自动注册
  • 优先使用 Pinia,而非 Vuex - API 更简单,更好地支持 TypeScript,并兼容组合式 API
  • 组合式函数 - 提取可复用逻辑(类似 React hooks)
  • v-memo - 优化开销大的渲染(类似 React.memo)
  • defineOptions - 在 script setup 中设置组件选项
  • 浅层响应式 - 对大型对象使用 shallowRef()

Svelte 5 开发

基于 Runes 的响应式

Svelte 5 Runes - 新的响应式系统:

<script lang="ts">
import type { User } from '$lib/types/user'

interface Props {
  userId: number
  onUpdate?: (user: User) => void
}

let { userId, onUpdate }: Props = $props()

// Reactive state with $state
let user = $state<User | null>(null)
let isLoading = $state(true)

// Derived state with $derived
let displayName = $derived(user?.name ?? 'Unknown')
let userAge = $derived.by(() => {
  if (!user?.birthDate) return null
  return calculateAge(user.birthDate)
})

// Effects with $effect
$effect(() => {
  // Runs when userId changes
  loadUser(userId)
})

async function loadUser(id: number) {
  isLoading = true
  user = await fetchUser(id)
  isLoading = false
}

function handleUpdate() {
  if (user) onUpdate?.(user)
}
</script>

{#if isLoading}
  <div>Loading...</div>
{:else if user}
  <div class="user-profile">
    <h2>{displayName}</h2>
    {#if userAge}
      <p>Age: {userAge}</p>
    {/if}
    <button onclick={handleUpdate}>Update</button>
  </div>
{/if}

<style>
.user-profile {
  padding: 1rem;
}
</style>

Svelte 5 Runes:

  • $state() - 响应式状态(替代用于实现响应性的 let)
  • $derived - 计算值(替代 $:)
  • $derived.by() - 复杂的派生状态
  • $effect() - 副作用(替代 $: 语句)
  • $props() - 使用解构的组件 props
  • $bindable() - props 的双向绑定
  • $inspect() - 调试响应式值
状态管理(Svelte Stores)
// stores/user.ts
import { writable, derived, readonly } from 'svelte/store'

function createUserStore() {
  const { subscribe, set, update } = writable<User[]>([])

  return {
    subscribe,
    setUsers: (users: User[]) => set(users),
    addUser: (user: User) => update(users => [...users, user]),
    removeUser: (id: number) => update(users => users.filter(u => u.id !== id)),
    reset: () => set([])
  }
}

export const users = createUserStore()
export const userCount = derived(users, $users => $users.length)

// Component usage (Svelte 4 style)
<script>
import { users } from '$lib/stores/user'
</script>

<p>Total users: {$users.length}</p>

// Or with runes (Svelte 5)
<script>
import { users } from '$lib/stores/user'
let currentUsers = $state($users)
</script>
SvelteKit 路由与数据加载
// src/routes/users/[id]/+page.ts
import type { PageLoad } from './$types'

export const load: PageLoad = async ({ params, fetch }) => {
  const user = await fetch(`/api/users/${params.id}`).then(r => r.json())

  return {
    user
  }
}

// src/routes/users/[id]/+page.svelte
<script lang="ts">
import type { PageData } from './$types'

let { data }: { data: PageData } = $props()
let { user } = $derived(data)
</script>

<h1>{user.name}</h1>

SvelteKit 模式:

  • +page.svelte - 页面组件
  • +page.ts - 页面数据加载(在服务端和客户端运行)
  • +page.server.ts - 仅在服务端运行的加载函数
  • +layout.svelte - 共享布局
  • +server.ts - API 端点
  • 表单操作 - 渐进增强
Svelte 5 最佳实践
  • 使用 Runes - 现代响应式(Svelte 5+)
  • 显式响应式 - 使用 $state(),而非隐式的 let
  • 优先使用 $derived,而非 $: - 意图更清晰,优化效果更好
  • 组件组合 - 使用插槽和代码片段
  • 使用 SvelteKit 构建应用 - 支持路由和 SSR 的全栈框架
  • 尽量减少 stores - 在组件中,Runes 可减少对 stores 的需求
  • 渐进增强 - 使用表单操作改善 UX

Angular 开发

独立组件(现代)
// user-profile.component.ts
import { Component, Input, Output, EventEmitter, signal, computed } from '@angular/core'
import { CommonModule } from '@angular/common'
import type { User } from '@/types/user'

@Component({
  selector: 'app-user-profile',
  standalone: true,
  imports: [CommonModule],
  template: `
    <div class="user-profile" *ngIf="!isLoading(); else loading">
      <h2>{{ displayName() }}</h2>
      <p>Age: {{ userAge() }}</p>
      <button (click)="handleUpdate()">Update</button>
    </div>
    <ng-template #loading>
      <div>Loading...</div>
    </ng-template>
  `,
  styles: [`
    .user-profile {
      padding: 1rem;
    }
  `]
})
export class UserProfileComponent {
  @Input({ required: true }) userId!: number
  @Output() userUpdate = new EventEmitter<User>()

  // Signals - reactive primitives
  user = signal<User | null>(null)
  isLoading = signal(true)

  // Computed signals
  displayName = computed(() => this.user()?.name ?? 'Unknown')
  userAge = computed(() => {
    const birthDate = this.user()?.birthDate
    return birthDate ? this.calculateAge(birthDate) : null
  })

  async ngOnInit() {
    this.user.set(await this.fetchUser(this.userId))
    this.isLoading.set(false)
  }

  handleUpdate() {
    const currentUser = this.user()
    if (currentUser) this.userUpdate.emit(currentUser)
  }
}

Angular Signals - 新的响应式系统(v16+):

  • signal() - 可写的响应式值
  • computed() - 派生状态
  • effect() - 副作用
  • .set()、.update() - 修改 signal 值
  • () - 读取 signal 值(作为函数调用)
状态管理(Services + Signals)
// services/user.service.ts
import { Injectable, signal, computed } from '@angular/core'
import { HttpClient } from '@angular/common/http'

@Injectable({ providedIn: 'root' })
export class UserService {
  private users = signal<User[]>([])
  private currentUser = signal<User | null>(null)

  // Public computed signals
  readonly userCount = computed(() => this.users().length)
  readonly isAuthenticated = computed(() => this.currentUser() !== null)

  constructor(private http: HttpClient) {}

  async fetchUsers() {
    const users = await this.http.get<User[]>('/api/users').toPromise()
    this.users.set(users)
  }

  setCurrentUser(user: User) {
    this.currentUser.set(user)
  }
}

// Component usage
export class MyComponent {
  constructor(public userService: UserService) {}

  // Access in template
  // {{ userService.userCount() }}
}
路由(Angular Router)
// app.routes.ts
import { Routes } from '@angular/router'

export const routes: Routes = [
  {
    path: '',
    loadComponent: () => import('./home/home.component').then(m => m.HomeComponent)
  },
  {
    path: 'users/:id',
    loadComponent: () => import('./users/user-detail.component').then(m => m.UserDetailComponent)
  }
]

// Component with route params
import { Component } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'

export class UserDetailComponent {
  userId = signal<string>('')

  constructor(
    private route: ActivatedRoute,
    private router: Router
  ) {
    this.userId.set(this.route.snapshot.paramMap.get('id') ?? '')
  }

  goBack() {
    this.router.navigate(['/'])
  }
}
数据获取(RxJS + Signals)
import { Component, signal } from '@angular/core'
import { HttpClient } from '@angular/common/http'
import { toSignal } from '@angular/core/rxjs-interop'

export class UserListComponent {
  private http = inject(HttpClient)

  // Convert Observable to Signal
  users = toSignal(this.http.get<User[]>('/api/users'), { initialValue: [] })

  // Or manual signal management
  manualUsers = signal<User[]>([])

  async loadUsers() {
    const users = await this.http.get<User[]>('/api/users').toPromise()
    this.manualUsers.set(users)
  }
}
Angular 最佳实践
  • 独立组件 - 自 v17 起为默认方式(无需 NgModules)
  • 优先使用 Signals,而非 RxJS - 更简单的状态响应式处理
  • toSignal - 在需要时将 Observables 转换为 Signals
  • inject() - 现代依赖注入(无需构造函数)
  • 延迟加载 - 路由使用 loadComponent
  • OnPush 变更检测 - 优化渲染
  • 类型化表单 - 使用 FormGroup<T> 确保类型安全

框架无关模式

状态管理对比
模式ReactVue 3Svelte 5Angular
本地状态useStateref()$state()signal()
派生状态useMemocomputed()$derivedcomputed()
副作用useEffectwatch/watchEffect$effect()effect()
全局状态Zustand/ContextPiniaStoresServices
异步状态TanStack QueryVueQuery/ComposablesStoresRxJS/Signals
组件组合模式

Props/Events 模式(所有框架):

  • 父组件通过 props 向下传递数据
  • 子组件向上触发事件
  • 单向数据流

Slots/Children 模式:

// React
<Layout>
  <Header />
  <Content />
</Layout>

// Vue
<Layout>
  <template #header><Header /></template>
  <template #content><Content /></template>
</Layout>

// Svelte
<Layout>
  <Header slot="header" />
  <Content slot="content" />
</Layout>

// Angular
<app-layout>
  <app-header header></app-header>
  <app-content content></app-content>
</app-layout>
路由模式

基于文件的路由:

  • Next.js(React)、Nuxt(Vue)、SvelteKit(Svelte)
  • 文件夹结构定义路由
  • 使用 [id] 表示动态片段

编程式路由:

  • React Router、Vue Router、Angular Router
  • 在配置中定义路由
  • 更灵活,但也更冗长
性能优化

通用技术:

  1. 代码拆分 - 延迟加载路由和大型组件
  2. 记忆化 - 缓存开销较大的计算
  3. 虚拟滚动 - 仅渲染可见项目
  4. 防抖 - 降低开销较大的操作频率(搜索、调整大小)
  5. 图像优化 - 延迟加载、响应式图像、现代格式
  6. 包分析 - 找出并移除大型依赖项

框架特定技术:

  • React: React.memo、useMemo、useCallback、Suspense
  • Vue: v-memo、shallowRef、markRaw、KeepAlive
  • Svelte: 自动优化、$derived、极简运行时
  • Angular: OnPush、signals、trackBy、纯管道

相关技能

重要:对于 UI/UX 设计工作,请调用专用技能:

Skill("ui-ux-pro-max")  → UI/UX design, visual hierarchy, color theory, spacing, typography

UI/设计:

  • ui-ux-pro-max:UI/UX 设计原则、视觉层次、色彩理论、间距系统、排版。设计决策、美化 UI、选择颜色/字体和布局设计时,请使用此技能。
  • ui-design-system:组件设计系统、无障碍设计、设计令牌
  • ui-styling:Tailwind CSS、适用于所有框架的样式模式

后端集成:

  • backend-development:前端使用的 API 模式
  • better-auth:身份验证实现(适用于所有框架)

全栈框架:

  • web-frameworks:深入了解 Next.js(React)、Nuxt(Vue)、SvelteKit(Svelte)

开发:

  • debugging:与框架无关的调试策略
  • refactoring-expert:代码质量和重构模式
  • chrome-devtools:浏览器调试、性能分析

何时调用 ui-ux-pro-max

遇到以下情况时,调用 Skill("ui-ux-pro-max"):

  • 设计新的 UI 组件或页面
  • 选择调色板、排版或间距
  • 改进视觉层次或布局
  • 让界面显得专业、现代、整洁
  • 用户提到:难看、不一致、杂乱、需要设计帮助
  • 构建仪表板、管理面板或 SaaS 界面

技能状态:覆盖多种框架,并支持渐进式披露

评论

支持 Markdown