AI 代码生成教程
本教程将教你如何使用 Trae AI 的代码生成功能,从简单的代码片段到复杂的应用架构,让 AI 成为你的编程助手。
概述
Trae AI 代码生成功能可以帮你:
- 快速生成样板代码
- 创建完整的组件和函数
- 实现复杂的业务逻辑
- 生成测试代码
- 创建配置文件
- 自动化重复性任务
快速开始
激活代码生成
有多种方式触发代码生成:
- 快捷键:
Ctrl+Shift+G(Windows/Linux) 或Cmd+Shift+G(macOS) - 右键菜单:在编辑器中右键 → "生成代码"
- 命令面板:
Ctrl+Shift+P→ "AI: 生成代码" - 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); // true2. 类生成
输入提示:
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
- 提供代码风格示例
- 使用项目模板
问题:生成的代码过于复杂
- 分步骤生成
- 明确具体需求
- 从简单开始迭代
优化技巧
- 使用代码模板:为常用模式创建模板
- 保存代码片段:将生成的好代码保存为片段
- 定期更新:保持 AI 模型和工具的最新版本
- 团队协作:分享有用的提示和模式
下一步
现在你已经掌握了 AI 代码生成的技巧,可以继续学习:
记住,AI 代码生成是一个强大的工具,但最重要的是理解生成的代码并根据需要进行调整!