# 前端开发指南 ## 1. 开发环境搭建 ### 1.1 安装依赖 ```bash # 安装Node.js # 推荐版本:18.x 或更高 # 进入frontend目录 cd frontend # 安装依赖 npm install ``` ### 1.2 环境变量配置 ```bash # 复制环境变量模板 cp .env.example .env # 编辑.env文件 VITE_API_BASE_URL=http://localhost:5000/api/v1 VITE_APP_TITLE=海洋项目管理系统 ``` ### 1.3 启动开发服务器 ```bash # 启动开发服务器 npm run dev # 访问 http://localhost:3000 ``` ### 1.4 常用命令 ```bash # 开发 npm run dev # 构建 npm run build # 预览构建 npm run preview # 代码检查 npm run lint # 代码格式化 npm run format # 运行测试 npm run test # 测试覆盖率 npm run test:coverage ``` ## 2. 代码规范 ### 2.1 ESLint配置 ```javascript // .eslintrc.js module.exports = { root: true, env: { browser: true, es2021: true, node: true, }, extends: [ 'eslint:recommended', 'plugin:react/recommended', 'plugin:react-hooks/recommended', 'plugin:react/jsx-runtime', ], parserOptions: { ecmaFeatures: { jsx: true, }, ecmaVersion: 'latest', sourceType: 'module', }, plugins: ['react', 'react-hooks'], rules: { 'react/prop-types': 'off', 'react/react-in-jsx-scope': 'off', 'no-console': ['warn', { allow: ['warn', 'error'] }], }, settings: { react: { version: 'detect', }, }, }; ``` ### 2.2 Prettier配置 ```javascript // .prettierrc { "semi": true, "singleQuote": true, "tabWidth": 2, "trailingComma": "es5", "printWidth": 100, "arrowParens": "avoid", "endOfLine": "lf" } ``` ### 2.3 Git提交规范 ``` 格式:[类型] 简短描述 类型: - feat: 新功能 - fix: 修复bug - style: 代码格式调整 - refactor: 重构 - test: 测试 - docs: 文档 - chore: 构建/工具链 示例: [frontend] feat: 添加项目列表页面 [frontend] fix: 修复登录后Token未保存的问题 [frontend] style: 统一代码格式 [frontend] refactor: 重构API服务模块 [frontend] test: 添加组件单元测试 [frontend] docs: 更新开发文档 [frontend] chore: 更新依赖版本 ``` ## 3. 目录结构说明 ### 3.1 src目录 ``` src/ ├── assets/ # 静态资源 │ ├── images/ # 图片 │ ├── fonts/ # 字体 │ └── styles/ # 样式文件 ├── components/ # 组件 │ ├── Layout/ # 布局组件 │ ├── Common/ # 通用组件 │ └── Business/ # 业务组件 ├── pages/ # 页面组件 ├── contexts/ # Context上下文 ├── hooks/ # 自定义Hooks ├── services/ # API服务 ├── utils/ # 工具函数 ├── config/ # 配置文件 └── router/ # 路由配置 ``` ### 3.2 文件命名规范 ``` 组件:PascalCase - Button.jsx - ProjectList.jsx - UserForm.jsx Hooks:camelCase - useAuth.js - useTable.js - useApi.js 工具函数:camelCase - formatDate.js - formatMoney.js - validate.js 样式文件:kebab-case - button.css - project-list.css - user-form.css ``` ## 4. 组件开发规范 ### 4.1 函数式组件 ```jsx // 推荐:使用函数式组件 + Hooks import React, { useState, useEffect } from 'react'; const MyComponent = ({ title, data }) => { const [loading, setLoading] = useState(false); useEffect(() => { // 副作用逻辑 }, []); return
{title}
; }; export default MyComponent; ``` ### 4.2 Props类型检查 ```jsx import PropTypes from 'prop-types'; const MyComponent = ({ title, count, onAdd }) => { return
{title}: {count}
; }; MyComponent.propTypes = { title: PropTypes.string.isRequired, count: PropTypes.number, onAdd: PropTypes.func, }; MyComponent.defaultProps = { count: 0, onAdd: () => {}, }; export default MyComponent; ``` ### 4.3 事件处理 ```jsx // 推荐:使用箭头函数或bind绑定 const MyComponent = () => { const handleClick = () => { console.log('Clicked'); }; return ; }; // 不推荐:在JSX中直接定义函数 const MyComponent = () => { return ; }; ``` ## 5. Hooks使用规范 ### 5.1 useState ```jsx // 基本用法 const [count, setCount] = useState(0); // 函数式更新 const [count, setCount] = useState(0); const increment = () => setCount(prev => prev + 1); // 对象更新 const [user, setUser] = useState({ name: '', age: 0 }); const updateName = (name) => setUser(prev => ({ ...prev, name })); ``` ### 5.2 useEffect ```jsx // 副作用 useEffect(() => { // 执行副作用 return () => { // 清理函数 }; }, [dependencies]); // 空依赖数组:只在挂载时执行一次 useEffect(() => { console.log('Component mounted'); }, []); // 依赖数组为空时,不要在依赖数组中省略 // 错误示例 useEffect(() => { fetchUser(userId); }, []); // eslint-disable-line react-hooks/exhaustive-deps // 正确示例 useEffect(() => { fetchUser(userId); }, [userId]); ``` ### 5.3 useMemo和useCallback ```jsx // useMemo:缓存计算结果 const expensiveValue = useMemo(() => { return computeExpensiveValue(a, b); }, [a, b]); // useCallback:缓存函数 const handleClick = useCallback(() => { doSomething(a, b); }, [a, b]); ``` ### 5.4 自定义Hooks ```jsx // 自定义Hook以use开头 const useFetch = (url) => { const [data, setData] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); useEffect(() => { const fetchData = async () => { setLoading(true); try { const response = await fetch(url); setData(await response.json()); } catch (err) { setError(err); } finally { setLoading(false); } }; fetchData(); }, [url]); return { data, loading, error }; }; ``` ## 6. 样式开发规范 ### 6.1 CSS模块 ```jsx // MyComponent.jsx import styles from './MyComponent.module.css'; const MyComponent = () => { return
Content
; }; ``` ### 6.2 CSS-in-JS(可选) ```jsx // 使用styled-components或emotion import styled from 'styled-components'; const StyledDiv = styled.div` padding: 20px; background: #f0f0f0; &:hover { background: #e0e0e0; } `; const MyComponent = () => { return Content; }; ``` ### 6.3 Tailwind CSS(可选) ```jsx // 使用Tailwind CSS工具类 const MyComponent = () => { return (
Content
); }; ``` ## 7. 状态管理规范 ### 7.1 使用Context API ```jsx // Context定义 import { createContext, useContext } from 'react'; const MyContext = createContext(); export const MyProvider = ({ children }) => { const [state, setState] = useState(initialState); return ( {children} ); }; export const useMyContext = () => { const context = useContext(MyContext); if (!context) { throw new Error('useMyContext must be used within MyProvider'); } return context; }; ``` ### 7.2 状态分类 ```jsx // 1. 本地状态:使用useState const [value, setValue] = useState(''); // 2. 上下文状态:使用Context const { user, setUser } = useAuth(); // 3. 表单状态:使用Ant Design Form const [form] = Form.useForm(); // 4. URL状态:使用useSearchParams const [searchParams, setSearchParams] = useSearchParams(); ``` ## 8. 路由开发规范 ### 8.1 使用React Router ```jsx import { Routes, Route, Navigate } from 'react-router-dom'; const Router = () => { return ( } /> } /> } /> } /> ); }; ``` ### 8.2 路由参数 ```jsx import { useParams, useSearchParams } from 'react-router-dom'; const ProjectDetail = () => { const { id } = useParams(); const [searchParams] = useSearchParams(); const keyword = searchParams.get('keyword') || ''; return
Project ID: {id}
; }; ``` ### 8.3 路由守卫 ```jsx const PrivateRoute = ({ children }) => { const { isAuthenticated } = useAuth(); if (!isAuthenticated) { return ; } return children; }; ``` ## 9. API调用规范 ### 9.1 使用Axios ```jsx import { useEffect } from 'react'; import { projectAPI } from '../services/project'; const ProjectList = () => { const [list, setList] = useState([]); const [loading, setLoading] = useState(false); useEffect(() => { const fetchList = async () => { setLoading(true); try { const data = await projectAPI.getList(); setList(data.items); } catch (error) { console.error('Fetch error:', error); } finally { setLoading(false); } }; fetchList(); }, []); return
{/* 渲染列表 */}
; }; ``` ### 9.2 使用自定义Hooks ```jsx import { useList } from '../hooks/useList'; import { projectAPI } from '../services/project'; const ProjectList = () => { const { list, loading, pagination, handleTableChange } = useList( projectAPI.getList ); return ; }; ``` ## 10. 错误处理规范 ### 10.1 错误边界 ```jsx class ErrorBoundary extends React.Component { state = { hasError: false, error: null }; static getDerivedStateFromError(error) { return { hasError: true, error }; } componentDidCatch(error, errorInfo) { console.error('Error:', error, errorInfo); } render() { if (this.state.hasError) { return
Something went wrong.
; } return this.props.children; } } // 使用 ``` ### 10.2 错误处理组件 ```jsx const ErrorFallback = ({ error, resetErrorBoundary }) => { return (

Something went wrong:

{error.message}
); }; ``` ## 11. 性能优化 ### 11.1 代码分割 ```jsx import { lazy, Suspense } from 'react'; const ProjectList = lazy(() => import('./pages/Projects/ProjectList')); const ProjectDetail = lazy(() => import('./pages/Projects/ProjectDetail')); const App = () => { return ( }> } /> } /> ); }; ``` ### 11.2 React.memo ```jsx const ExpensiveComponent = React.memo(({ data }) => { // 渲染逻辑 }); // 自定义比较函数 const MyComponent = React.memo(({ a, b }) => { // 渲染逻辑 }, (prevProps, nextProps) => { return prevProps.a === nextProps.a && prevProps.b === nextProps.b; }); ``` ### 11.3 useMemo和useCallback ```jsx const MyComponent = ({ data, onUpdate }) => { // 缓存计算结果 const sortedData = useMemo(() => { return data.sort((a, b) => a.id - b.id); }, [data]); // 缓存函数 const handleClick = useCallback(() => { onUpdate(sortedData); }, [onUpdate, sortedData]); return
Content
; }; ``` ## 12. 测试规范 ### 12.1 组件测试 ```jsx import { render, screen, fireEvent } from '@testing-library/react'; import Button from './Button'; describe('Button Component', () => { test('renders button with children', () => { render(); expect(screen.getByText('Click me')).toBeInTheDocument(); }); test('calls onClick when clicked', () => { const handleClick = jest.fn(); render(); fireEvent.click(screen.getByText('Click')); expect(handleClick).toHaveBeenCalledTimes(1); }); }); ``` ### 12.2 Hooks测试 ```jsx import { renderHook, act } from '@testing-library/react'; import { useCounter } from './useCounter'; describe('useCounter', () => { test('should increment counter', () => { const { result } = renderHook(() => useCounter()); expect(result.current.count).toBe(0); act(() => { result.current.increment(); }); expect(result.current.count).toBe(1); }); }); ``` ### 12.3 集成测试 ```jsx import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import { BrowserRouter } from 'react-router-dom'; import App from './App'; const renderWithRouter = (component) => { return render({component}); }; test('user can login', async () => { renderWithRouter(); fireEvent.change(screen.getByLabelText('Username'), { target: { value: 'admin' }, }); fireEvent.change(screen.getByLabelText('Password'), { target: { value: 'password' }, }); fireEvent.click(screen.getByText('Login')); await waitFor(() => { expect(screen.getByText('Dashboard')).toBeInTheDocument(); }); }); ``` ## 13. 调试技巧 ### 13.1 React DevTools ```jsx // 安装React DevTools浏览器扩展 // 可以查看组件树、props、state、Hooks等 ``` ### 13.2 Console日志 ```jsx // 开发环境下的调试日志 if (import.meta.env.DEV) { console.log('Debug:', { data, loading }); } // 生产环境下自动移除 ``` ### 13.3 性能分析 ```jsx // 使用React Profiler分析性能 import { Profiler } from 'react'; const onRenderCallback = (id, phase, actualDuration) => { console.log(`${id} ${phase} took ${actualDuration}ms`); }; ``` ## 14. 部署规范 ### 14.1 构建配置 ```javascript // vite.config.js import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], base: '/app/', // 基础路径 build: { outDir: 'dist', sourcemap: false, // 生产环境关闭sourcemap chunkSizeWarningLimit: 1000, }, server: { port: 3000, proxy: { '/api': { target: 'http://localhost:5000', changeOrigin: true, }, }, }, }); ``` ### 14.2 环境变量 ```bash # .env.development VITE_API_BASE_URL=http://localhost:5000/api/v1 # .env.production VITE_API_BASE_URL=https://api.example.com/api/v1 ``` ### 14.3 Docker部署 ```dockerfile # Dockerfile FROM node:18-alpine as builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] ``` ## 15. 最佳实践 ### 15.1 组件设计 - 单一职责原则:每个组件只做一件事 - 组件大小控制在300行以内 - 合理拆分组件,提高复用性 - 使用组合而非继承 ### 15.2 性能优化 - 使用React.memo避免不必要的渲染 - 使用useMemo缓存计算结果 - 使用useCallback缓存函数 - 使用懒加载减少初始加载时间 ### 15.3 代码质量 - 遵循ESLint和Prettier规范 - 编写单元测试 - 添加必要的注释 - 保持代码简洁清晰 ### 15.4 安全性 - 避免直接渲染用户输入 - 使用HTTPS - Token存储安全 - 设置适当的CORS策略 ## 16. 常见问题 ### 16.1 如何处理跨域? ```javascript // vite.config.js export default defineConfig({ server: { proxy: { '/api': { target: 'http://localhost:5000', changeOrigin: true, }, }, }, }); ``` ### 16.2 如何优化首屏加载? ```jsx // 使用路由懒加载 const Dashboard = lazy(() => import('./pages/Dashboard')); // 使用Suspense包裹 }> ``` ### 16.3 如何处理表单验证? ```jsx import { Form, Input, Button } from 'antd'; const MyForm = () => { const [form] = Form.useForm(); const onFinish = (values) => { console.log('Form values:', values); }; return (
); }; ``` --- **文档维护**: 前端程序员 **文档类型**: 前端开发指南 **最后更新**: 2026-01-25