Skip to content

AI 代码生成教程

本教程将教你如何使用 Trae AI 的代码生成功能,从简单的代码片段到复杂的应用架构,让 AI 成为你的编程助手。

概述

Trae AI 代码生成功能可以帮你:

  • 快速生成样板代码
  • 创建完整的组件和函数
  • 实现复杂的业务逻辑
  • 生成测试代码
  • 创建配置文件
  • 自动化重复性任务

快速开始

激活代码生成

有多种方式触发代码生成:

  1. 快捷键Ctrl+Shift+G (Windows/Linux) 或 Cmd+Shift+G (macOS)
  2. 右键菜单:在编辑器中右键 → "生成代码"
  3. 命令面板Ctrl+Shift+P → "AI: 生成代码"
  4. AI 聊天:在聊天中直接请求生成代码

代码生成触发器

Trae AI 支持多种触发方式:

1. 注释触发

javascript
// 创建一个用户注册表单组件
// AI 会自动检测注释并生成相应代码

2. 函数签名触发

typescript
// 只写函数签名,AI 会生成实现
function calculateTax(income: number, taxRate: number): number {
  // AI 将在这里生成实现
}

3. 选中代码生成

选中一段代码,然后使用快捷键生成相关代码。

基础代码生成

1. 函数生成

输入提示:

javascript
// 创建一个函数来验证邮箱格式

生成结果:

javascript
/**
 * 验证邮箱格式是否正确
 * @param {string} email - 要验证的邮箱地址
 * @returns {boolean} 邮箱格式是否有效
 */
function validateEmail(email) {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
}

// 使用示例
const isValid = validateEmail('user@example.com');
console.log(isValid); // true

2. 类生成

输入提示:

typescript
// 创建一个用户管理类

生成结果:

typescript
interface User {
  id: string;
  name: string;
  email: string;
  createdAt: Date;
}

class UserManager {
  private users: Map<string, User> = new Map();

  /**
   * 添加新用户
   */
  addUser(userData: Omit<User, 'id' | 'createdAt'>): User {
    const user: User = {
      id: this.generateId(),
      ...userData,
      createdAt: new Date()
    };
    
    this.users.set(user.id, user);
    return user;
  }

  /**
   * 根据ID获取用户
   */
  getUserById(id: string): User | undefined {
    return this.users.get(id);
  }

  /**
   * 更新用户信息
   */
  updateUser(id: string, updates: Partial<Omit<User, 'id' | 'createdAt'>>): User | null {
    const user = this.users.get(id);
    if (!user) return null;

    const updatedUser = { ...user, ...updates };
    this.users.set(id, updatedUser);
    return updatedUser;
  }

  /**
   * 删除用户
   */
  deleteUser(id: string): boolean {
    return this.users.delete(id);
  }

  /**
   * 获取所有用户
   */
  getAllUsers(): User[] {
    return Array.from(this.users.values());
  }

  private generateId(): string {
    return Math.random().toString(36).substr(2, 9);
  }
}

3. React 组件生成

输入提示:

jsx
// 创建一个可复用的按钮组件

生成结果:

tsx
import React from 'react';
import './Button.css';

interface ButtonProps {
  children: React.ReactNode;
  variant?: 'primary' | 'secondary' | 'danger';
  size?: 'small' | 'medium' | 'large';
  disabled?: boolean;
  loading?: boolean;
  onClick?: () => void;
  type?: 'button' | 'submit' | 'reset';
}

const Button: React.FC<ButtonProps> = ({
  children,
  variant = 'primary',
  size = 'medium',
  disabled = false,
  loading = false,
  onClick,
  type = 'button'
}) => {
  const handleClick = () => {
    if (!disabled && !loading && onClick) {
      onClick();
    }
  };

  const className = [
    'btn',
    `btn--${variant}`,
    `btn--${size}`,
    disabled && 'btn--disabled',
    loading && 'btn--loading'
  ].filter(Boolean).join(' ');

  return (
    <button
      type={type}
      className={className}
      onClick={handleClick}
      disabled={disabled || loading}
    >
      {loading && <span className="btn__spinner" />}
      <span className="btn__content">{children}</span>
    </button>
  );
};

export default Button;

对应的 CSS 文件:

css
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 6px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.2s ease;
  position: relative;
}

/* 尺寸变体 */
.btn--small {
  padding: 6px 12px;
  font-size: 14px;
}

.btn--medium {
  padding: 8px 16px;
  font-size: 16px;
}

.btn--large {
  padding: 12px 24px;
  font-size: 18px;
}

/* 颜色变体 */
.btn--primary {
  background-color: #007bff;
  color: white;
}

.btn--primary:hover {
  background-color: #0056b3;
}

.btn--secondary {
  background-color: #6c757d;
  color: white;
}

.btn--secondary:hover {
  background-color: #545b62;
}

.btn--danger {
  background-color: #dc3545;
  color: white;
}

.btn--danger:hover {
  background-color: #c82333;
}

/* 状态 */
.btn--disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.btn--loading .btn__content {
  opacity: 0.7;
}

.btn__spinner {
  width: 16px;
  height: 16px;
  border: 2px solid transparent;
  border-top: 2px solid currentColor;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin-right: 8px;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

高级代码生成

1. API 集成代码

输入提示:

typescript
// 创建一个产品 API 服务类

生成结果:

typescript
interface Product {
  id: string;
  name: string;
  description: string;
  price: number;
  category: string;
  imageUrl: string;
  inStock: boolean;
  createdAt: string;
  updatedAt: string;
}

interface ProductFilters {
  category?: string;
  minPrice?: number;
  maxPrice?: number;
  inStock?: boolean;
  search?: string;
}

interface PaginatedResponse<T> {
  data: T[];
  total: number;
  page: number;
  limit: number;
  totalPages: number;
}

class ProductService {
  private baseUrl: string;
  private apiKey: string;

  constructor(baseUrl: string, apiKey: string) {
    this.baseUrl = baseUrl;
    this.apiKey = apiKey;
  }

  /**
   * 获取产品列表
   */
  async getProducts(
    page: number = 1,
    limit: number = 10,
    filters?: ProductFilters
  ): Promise<PaginatedResponse<Product>> {
    const params = new URLSearchParams({
      page: page.toString(),
      limit: limit.toString(),
      ...filters
    });

    const response = await fetch(`${this.baseUrl}/products?${params}`, {
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json'
      }
    });

    if (!response.ok) {
      throw new Error(`获取产品失败: ${response.statusText}`);
    }

    return response.json();
  }

  /**
   * 根据ID获取单个产品
   */
  async getProductById(id: string): Promise<Product> {
    const response = await fetch(`${this.baseUrl}/products/${id}`, {
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json'
      }
    });

    if (!response.ok) {
      throw new Error(`获取产品失败: ${response.statusText}`);
    }

    return response.json();
  }

  /**
   * 创建新产品
   */
  async createProduct(productData: Omit<Product, 'id' | 'createdAt' | 'updatedAt'>): Promise<Product> {
    const response = await fetch(`${this.baseUrl}/products`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(productData)
    });

    if (!response.ok) {
      throw new Error(`创建产品失败: ${response.statusText}`);
    }

    return response.json();
  }

  /**
   * 更新产品
   */
  async updateProduct(
    id: string,
    updates: Partial<Omit<Product, 'id' | 'createdAt' | 'updatedAt'>>
  ): Promise<Product> {
    const response = await fetch(`${this.baseUrl}/products/${id}`, {
      method: 'PUT',
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(updates)
    });

    if (!response.ok) {
      throw new Error(`更新产品失败: ${response.statusText}`);
    }

    return response.json();
  }

  /**
   * 删除产品
   */
  async deleteProduct(id: string): Promise<void> {
    const response = await fetch(`${this.baseUrl}/products/${id}`, {
      method: 'DELETE',
      headers: {
        'Authorization': `Bearer ${this.apiKey}`
      }
    });

    if (!response.ok) {
      throw new Error(`删除产品失败: ${response.statusText}`);
    }
  }

  /**
   * 搜索产品
   */
  async searchProducts(query: string, filters?: ProductFilters): Promise<Product[]> {
    const params = new URLSearchParams({
      q: query,
      ...filters
    });

    const response = await fetch(`${this.baseUrl}/products/search?${params}`, {
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json'
      }
    });

    if (!response.ok) {
      throw new Error(`搜索产品失败: ${response.statusText}`);
    }

    const result = await response.json();
    return result.data;
  }
}

// 使用示例
const productService = new ProductService('https://api.example.com', 'your-api-key');

// 获取产品列表
const products = await productService.getProducts(1, 20, {
  category: 'electronics',
  inStock: true
});

// 创建新产品
const newProduct = await productService.createProduct({
  name: 'iPhone 15',
  description: '最新款 iPhone',
  price: 999,
  category: 'electronics',
  imageUrl: 'https://example.com/iphone15.jpg',
  inStock: true
});

2. 自定义 Hooks 生成

输入提示:

typescript
// 创建一个用于数据获取的自定义 Hook

生成结果:

typescript
import { useState, useEffect, useCallback, useRef } from 'react';

interface UseApiOptions<T> {
  initialData?: T;
  immediate?: boolean;
  onSuccess?: (data: T) => void;
  onError?: (error: Error) => void;
  retryCount?: number;
  retryDelay?: number;
}

interface UseApiReturn<T> {
  data: T | null;
  loading: boolean;
  error: Error | null;
  execute: () => Promise<void>;
  retry: () => Promise<void>;
  reset: () => void;
}

function useApi<T>(
  apiFunction: () => Promise<T>,
  options: UseApiOptions<T> = {}
): UseApiReturn<T> {
  const {
    initialData = null,
    immediate = true,
    onSuccess,
    onError,
    retryCount = 3,
    retryDelay = 1000
  } = options;

  const [data, setData] = useState<T | null>(initialData);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<Error | null>(null);
  const retryCountRef = useRef(0);
  const mountedRef = useRef(true);

  useEffect(() => {
    return () => {
      mountedRef.current = false;
    };
  }, []);

  const execute = useCallback(async () => {
    if (!mountedRef.current) return;

    setLoading(true);
    setError(null);

    try {
      const result = await apiFunction();
      
      if (mountedRef.current) {
        setData(result);
        retryCountRef.current = 0;
        onSuccess?.(result);
      }
    } catch (err) {
      if (mountedRef.current) {
        const error = err instanceof Error ? err : new Error('Unknown error');
        setError(error);
        onError?.(error);
      }
    } finally {
      if (mountedRef.current) {
        setLoading(false);
      }
    }
  }, [apiFunction, onSuccess, onError]);

  const retry = useCallback(async () => {
    if (retryCountRef.current < retryCount) {
      retryCountRef.current += 1;
      
      // 延迟重试
      await new Promise(resolve => setTimeout(resolve, retryDelay));
      
      if (mountedRef.current) {
        await execute();
      }
    }
  }, [execute, retryCount, retryDelay]);

  const reset = useCallback(() => {
    setData(initialData);
    setLoading(false);
    setError(null);
    retryCountRef.current = 0;
  }, [initialData]);

  useEffect(() => {
    if (immediate) {
      execute();
    }
  }, [execute, immediate]);

  return {
    data,
    loading,
    error,
    execute,
    retry,
    reset
  };
}

// 使用示例
const UserProfile = ({ userId }: { userId: string }) => {
  const {
    data: user,
    loading,
    error,
    retry
  } = useApi(
    () => fetch(`/api/users/${userId}`).then(res => res.json()),
    {
      onSuccess: (user) => console.log('用户加载成功:', user),
      onError: (error) => console.error('加载失败:', error),
      retryCount: 3
    }
  );

  if (loading) return <div>加载中...</div>;
  if (error) return (
    <div>
      <p>加载失败: {error.message}</p>
      <button onClick={retry}>重试</button>
    </div>
  );
  if (!user) return <div>未找到用户</div>;

  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
};

export default useApi;

3. 状态管理代码生成

输入提示:

typescript
// 创建一个购物车状态管理 store

生成结果:

typescript
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

interface CartItem {
  id: string;
  name: string;
  price: number;
  quantity: number;
  imageUrl: string;
}

interface CartState {
  items: CartItem[];
  total: number;
  itemCount: number;
  
  // Actions
  addItem: (item: Omit<CartItem, 'quantity'>) => void;
  removeItem: (id: string) => void;
  updateQuantity: (id: string, quantity: number) => void;
  clearCart: () => void;
  getItemById: (id: string) => CartItem | undefined;
}

const useCartStore = create<CartState>()(n  persist(
    (set, get) => ({
      items: [],
      total: 0,
      itemCount: 0,

      addItem: (newItem) => {
        set((state) => {
          const existingItem = state.items.find(item => item.id === newItem.id);
          
          let updatedItems: CartItem[];
          
          if (existingItem) {
            // 如果商品已存在,增加数量
            updatedItems = state.items.map(item =>
              item.id === newItem.id
                ? { ...item, quantity: item.quantity + 1 }
                : item
            );
          } else {
            // 如果是新商品,添加到购物车
            updatedItems = [...state.items, { ...newItem, quantity: 1 }];
          }

          const total = updatedItems.reduce(
            (sum, item) => sum + item.price * item.quantity,
            0
          );
          
          const itemCount = updatedItems.reduce(
            (sum, item) => sum + item.quantity,
            0
          );

          return {
            items: updatedItems,
            total,
            itemCount
          };
        });
      },

      removeItem: (id) => {
        set((state) => {
          const updatedItems = state.items.filter(item => item.id !== id);
          
          const total = updatedItems.reduce(
            (sum, item) => sum + item.price * item.quantity,
            0
          );
          
          const itemCount = updatedItems.reduce(
            (sum, item) => sum + item.quantity,
            0
          );

          return {
            items: updatedItems,
            total,
            itemCount
          };
        });
      },

      updateQuantity: (id, quantity) => {
        if (quantity <= 0) {
          get().removeItem(id);
          return;
        }

        set((state) => {
          const updatedItems = state.items.map(item =>
            item.id === id ? { ...item, quantity } : item
          );
          
          const total = updatedItems.reduce(
            (sum, item) => sum + item.price * item.quantity,
            0
          );
          
          const itemCount = updatedItems.reduce(
            (sum, item) => sum + item.quantity,
            0
          );

          return {
            items: updatedItems,
            total,
            itemCount
          };
        });
      },

      clearCart: () => {
        set({
          items: [],
          total: 0,
          itemCount: 0
        });
      },

      getItemById: (id) => {
        return get().items.find(item => item.id === id);
      }
    }),
    {
      name: 'cart-storage',
      partialize: (state) => ({
        items: state.items,
        total: state.total,
        itemCount: state.itemCount
      })
    }
  )
);

// 使用示例组件
const CartComponent = () => {
  const { items, total, itemCount, addItem, removeItem, updateQuantity, clearCart } = useCartStore();

  return (
    <div className="cart">
      <h2>购物车 ({itemCount} 件商品)</h2>
      
      {items.length === 0 ? (
        <p>购物车为空</p>
      ) : (
        <>
          {items.map(item => (
            <div key={item.id} className="cart-item">
              <img src={item.imageUrl} alt={item.name} />
              <div className="item-details">
                <h3>{item.name}</h3>
                <p>¥{item.price}</p>
              </div>
              <div className="quantity-controls">
                <button onClick={() => updateQuantity(item.id, item.quantity - 1)}>
                  -
                </button>
                <span>{item.quantity}</span>
                <button onClick={() => updateQuantity(item.id, item.quantity + 1)}>
                  +
                </button>
              </div>
              <button onClick={() => removeItem(item.id)}>删除</button>
            </div>
          ))}
          
          <div className="cart-summary">
            <p>总计: ¥{total.toFixed(2)}</p>
            <button onClick={clearCart}>清空购物车</button>
            <button className="checkout-btn">去结算</button>
          </div>
        </>
      )}
    </div>
  );
};

export default useCartStore;

测试代码生成

1. 单元测试生成

输入提示:

typescript
// 为 validateEmail 函数生成测试

生成结果:

typescript
import { validateEmail } from '../utils/validation';

describe('validateEmail', () => {
  describe('有效邮箱', () => {
    test('应该接受标准邮箱格式', () => {
      const validEmails = [
        'user@example.com',
        'test.email@domain.co.uk',
        'user+tag@example.org',
        'user123@test-domain.com',
        'a@b.co'
      ];

      validEmails.forEach(email => {
        expect(validateEmail(email)).toBe(true);
      });
    });

    test('应该接受包含数字的邮箱', () => {
      expect(validateEmail('user123@example123.com')).toBe(true);
    });

    test('应该接受包含特殊字符的邮箱', () => {
      expect(validateEmail('user.name+tag@example.com')).toBe(true);
    });
  });

  describe('无效邮箱', () => {
    test('应该拒绝缺少 @ 符号的邮箱', () => {
      expect(validateEmail('userexample.com')).toBe(false);
    });

    test('应该拒绝缺少域名的邮箱', () => {
      expect(validateEmail('user@')).toBe(false);
    });

    test('应该拒绝缺少用户名的邮箱', () => {
      expect(validateEmail('@example.com')).toBe(false);
    });

    test('应该拒绝包含空格的邮箱', () => {
      expect(validateEmail('user @example.com')).toBe(false);
      expect(validateEmail('user@ example.com')).toBe(false);
    });

    test('应该拒绝多个 @ 符号的邮箱', () => {
      expect(validateEmail('user@@example.com')).toBe(false);
      expect(validateEmail('user@example@.com')).toBe(false);
    });

    test('应该拒绝空字符串', () => {
      expect(validateEmail('')).toBe(false);
    });

    test('应该拒绝 null 和 undefined', () => {
      expect(validateEmail(null as any)).toBe(false);
      expect(validateEmail(undefined as any)).toBe(false);
    });
  });

  describe('边界情况', () => {
    test('应该处理极长的邮箱地址', () => {
      const longEmail = 'a'.repeat(50) + '@' + 'b'.repeat(50) + '.com';
      expect(validateEmail(longEmail)).toBe(true);
    });

    test('应该处理最短的有效邮箱', () => {
      expect(validateEmail('a@b.c')).toBe(true);
    });
  });
});

2. 组件测试生成

输入提示:

typescript
// 为 Button 组件生成测试

生成结果:

typescript
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import Button from '../Button';

describe('Button 组件', () => {
  describe('渲染', () => {
    test('应该渲染按钮文本', () => {
      render(<Button>点击我</Button>);
      expect(screen.getByRole('button', { name: '点击我' })).toBeInTheDocument();
    });

    test('应该应用默认样式类', () => {
      render(<Button>测试</Button>);
      const button = screen.getByRole('button');
      expect(button).toHaveClass('btn', 'btn--primary', 'btn--medium');
    });
  });

  describe('变体', () => {
    test('应该应用正确的变体样式', () => {
      const { rerender } = render(<Button variant="secondary">测试</Button>);
      expect(screen.getByRole('button')).toHaveClass('btn--secondary');

      rerender(<Button variant="danger">测试</Button>);
      expect(screen.getByRole('button')).toHaveClass('btn--danger');
    });

    test('应该应用正确的尺寸样式', () => {
      const { rerender } = render(<Button size="small">测试</Button>);
      expect(screen.getByRole('button')).toHaveClass('btn--small');

      rerender(<Button size="large">测试</Button>);
      expect(screen.getByRole('button')).toHaveClass('btn--large');
    });
  });

  describe('交互', () => {
    test('应该在点击时调用 onClick', () => {
      const handleClick = jest.fn();
      render(<Button onClick={handleClick}>点击我</Button>);
      
      fireEvent.click(screen.getByRole('button'));
      expect(handleClick).toHaveBeenCalledTimes(1);
    });

    test('禁用时不应该调用 onClick', () => {
      const handleClick = jest.fn();
      render(
        <Button onClick={handleClick} disabled>
          禁用按钮
        </Button>
      );
      
      fireEvent.click(screen.getByRole('button'));
      expect(handleClick).not.toHaveBeenCalled();
    });

    test('加载时不应该调用 onClick', () => {
      const handleClick = jest.fn();
      render(
        <Button onClick={handleClick} loading>
          加载中
        </Button>
      );
      
      fireEvent.click(screen.getByRole('button'));
      expect(handleClick).not.toHaveBeenCalled();
    });
  });

  describe('状态', () => {
    test('禁用状态应该正确显示', () => {
      render(<Button disabled>禁用按钮</Button>);
      const button = screen.getByRole('button');
      
      expect(button).toBeDisabled();
      expect(button).toHaveClass('btn--disabled');
    });

    test('加载状态应该正确显示', () => {
      render(<Button loading>加载中</Button>);
      const button = screen.getByRole('button');
      
      expect(button).toBeDisabled();
      expect(button).toHaveClass('btn--loading');
      expect(screen.getByText('加载中')).toBeInTheDocument();
    });

    test('加载时应该显示加载指示器', () => {
      render(<Button loading>加载中</Button>);
      expect(document.querySelector('.btn__spinner')).toBeInTheDocument();
    });
  });

  describe('可访问性', () => {
    test('应该支持不同的按钮类型', () => {
      const { rerender } = render(<Button type="submit">提交</Button>);
      expect(screen.getByRole('button')).toHaveAttribute('type', 'submit');

      rerender(<Button type="reset">重置</Button>);
      expect(screen.getByRole('button')).toHaveAttribute('type', 'reset');
    });

    test('应该支持键盘导航', () => {
      const handleClick = jest.fn();
      render(<Button onClick={handleClick}>测试</Button>);
      
      const button = screen.getByRole('button');
      button.focus();
      
      fireEvent.keyDown(button, { key: 'Enter' });
      expect(handleClick).toHaveBeenCalled();
    });
  });
});

最佳实践

1. 清晰的提示

好的提示:

✅ 创建一个响应式的导航栏组件,支持移动端折叠菜单
✅ 实现一个带分页的数据表格,支持排序和筛选
✅ 生成一个用户认证的 Hook,包含登录、注销和状态管理

避免的提示:

❌ 写个组件
❌ 帮我做个功能
❌ 生成代码

2. 提供上下文

// 当前项目使用 React + TypeScript + Tailwind CSS
// 创建一个产品卡片组件,用于电商网站
// 需要显示产品图片、名称、价格、评分
// 支持添加到购物车和收藏功能

3. 指定技术栈

// 使用 Next.js + Prisma + PostgreSQL
// 创建用户管理的 API 路由
// 包含 CRUD 操作和数据验证

4. 迭代改进

第一步:生成基础组件
第二步:添加样式和动画
第三步:添加测试
第四步:优化性能

故障排除

常见问题

问题:生成的代码无法运行

  • 检查依赖是否安装
  • 确认 TypeScript 配置
  • 验证导入路径

问题:代码风格不一致

  • 配置 ESLint 和 Prettier
  • 提供代码风格示例
  • 使用项目模板

问题:生成的代码过于复杂

  • 分步骤生成
  • 明确具体需求
  • 从简单开始迭代

优化技巧

  1. 使用代码模板:为常用模式创建模板
  2. 保存代码片段:将生成的好代码保存为片段
  3. 定期更新:保持 AI 模型和工具的最新版本
  4. 团队协作:分享有用的提示和模式

下一步

现在你已经掌握了 AI 代码生成的技巧,可以继续学习:

记住,AI 代码生成是一个强大的工具,但最重要的是理解生成的代码并根据需要进行调整!

您的终极 AI 驱动 IDE 学习指南