# Web前端开发最佳实践 ## 1. 页面布局规范 ### 1.1 标题和查询条件区域 参考引航计划的布局方式,页面应包含以下区域: ```vue ``` ### 1.2 样式规范 ```css .page-container { padding: 15px; height: 100vh; overflow-y: auto; } .page-container h2 { margin: 0 0 15px 0; font-size: 18px; color: #303133; } .search-section { background: #fff; padding: 15px; margin-bottom: 15px; border-radius: 4px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .search-section h3 { margin: 0 0 12px 0; font-size: 15px; color: #606266; } .search-form { display: flex; flex-direction: column; gap: 12px; } .search-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; } .search-row .el-form-item { margin-bottom: 0; min-width: 200px; } .search-actions { display: flex; gap: 8px; margin-left: auto; } .action-section { margin-bottom: 15px; display: flex; gap: 8px; } .table-container { background: #fff; padding: 15px; border-radius: 4px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); flex: 1; display: flex; flex-direction: column; } ``` **关键间距说明:** - 页面容器padding:15px - 标题h2:font-size: 18px,margin-bottom: 15px - 查询条件区域padding:15px,margin-bottom: 15px - 标题h3:font-size: 15px,margin-bottom: 12px - search-row gap:12px - search-actions gap:8px - 操作按钮区域margin-bottom:15px - 表格容器padding:15px - 分页margin-top:15px - 对话框按钮gap:8px **注意:** 所有间距都应保持紧凑,避免过大的空白区域,确保界面紧凑、专业。 ## 2. 表格设计规范 ### 2.1 表格属性 ```vue ``` ### 2.2 列设计规范 - **序号列**:宽度50px,固定居中 - **选择列**:宽度55px,固定居中 - **操作列**:宽度120px,固定右侧 - **状态列**:宽度80px,居中显示,使用el-tag - **日期时间列**:宽度160px,居中显示 - **用户名列**:宽度100px - **账号列**:宽度100px - **用户角色列**:宽度150px - **企业微信账号列**:宽度120px - **其他文本列**:使用min-width,支持文本溢出显示 ```vue ``` **重要说明:** - 使用固定宽度(width)而不是最小宽度(min-width)可以避免标题栏分行 - 序号列使用50px而不是60px,更加紧凑 - 操作列使用120px,足够容纳两个按钮 - 状态列使用80px,足够显示状态标签 - 用户名和账号列使用100px,适合大多数情况 - 用户角色列使用150px,可以容纳多个角色名称(用逗号分隔) - 企业微信账号列使用120px,适合大多数微信号长度 - 日期时间列使用160px,可以完整显示日期时间格式 ### 2.3 日期时间格式化 ```javascript const formatDateTime = (dateStr) => { if (!dateStr) return '' const date = new Date(dateStr) const year = date.getFullYear() const month = String(date.getMonth() + 1).padStart(2, '0') const day = String(date.getDate()).padStart(2, '0') const hours = String(date.getHours()).padStart(2, '0') const minutes = String(date.getMinutes()).padStart(2, '0') const seconds = String(date.getSeconds()).padStart(2, '0') return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}` } ``` ## 3. 删除操作规范 ### 3.1 删除确认对话框 所有删除操作都必须显示确认对话框,防止误操作。 #### 单个删除 ```javascript const deleteUser = async (id) => { try { await ElMessageBox.confirm( '确定要删除该用户吗?删除后用户及其角色关联将被永久删除,不可恢复。', '删除确认', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' } ) await request.delete(`/user/delete/${id}`) ElMessage.success('删除成功') getUsers() } catch (error) { if (error !== 'cancel') { console.error('删除用户失败:', error) ElMessage.error('删除用户失败') } } } ``` #### 批量删除 ```javascript const deleteSelectedUsers = async () => { if (selectedUserIds.value.length === 0) { return } try { await ElMessageBox.confirm( `确定要删除选中的 ${selectedUserIds.value.length} 个用户吗?删除后用户及其角色关联将被永久删除,不可恢复。`, '删除确认', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' } ) await request.delete('/user/delete', { data: selectedUserIds.value }) ElMessage.success('删除成功') selectedUserIds.value = [] getUsers() } catch (error) { if (error !== 'cancel') { console.error('删除用户失败:', error) ElMessage.error('删除用户失败') } } } ``` ### 3.2 后端删除逻辑 删除主表数据时,必须先删除关联表数据。 ```java @Transactional public void deleteUsers(List userIds) { for (String userId : userIds) { // 先删除关联表数据 sysUserRoleRepository.deleteByUserId(userId); // 再删除主表数据 userRepository.deleteById(userId); } } ``` ## 4. 排序功能 ### 4.1 前端排序 ```javascript const handleSortChange = ({ prop, order }) => { if (order) { queryForm.value.sortBy = prop queryForm.value.sortOrder = order === 'ascending' ? 'asc' : 'desc' } else { queryForm.value.sortBy = null queryForm.value.sortOrder = null } getUsers() } ``` ### 4.2 后端排序 ```java public Page queryUsers(UserQuery query, Pageable pageable) { Sort sort = pageable.getSort(); if (query.getSortBy() != null && query.getSortOrder() != null) { sort = Sort.by( "asc".equalsIgnoreCase(query.getSortOrder()) ? Sort.Direction.ASC : Sort.Direction.DESC, query.getSortBy() ); } return userRepository.findAll(pageable.withSort(sort)); } ``` ## 5. API请求规范 ### 5.1 使用request.js 所有API请求都应该使用统一的request工具,自动处理认证和错误。 ```javascript import request from '@/utils/request' export const getUsers = (params) => { return request.get('/user/list', { params }) } export const createUser = (data) => { return request.post('/user/create', data) } export const deleteUser = (data) => { return request.delete('/user/delete', { data }) } ``` ### 5.2 错误处理 ```javascript try { await request.post('/api/endpoint', data) ElMessage.success('操作成功') } catch (error) { console.error('操作失败:', error) ElMessage.error('操作失败,请稍后重试') } ``` ## 6. 表单验证 ### 6.1 前端验证 ```vue ``` ### 6.2 后端验证 ```java public class UserCreateDTO { @NotBlank(message = "用户名不能为空") @Size(min = 2, max = 50, message = "用户名长度必须在2-50之间") private String name; @NotBlank(message = "账号不能为空") private String loginId; @NotBlank(message = "密码不能为空") @Size(min = 6, message = "密码长度不能少于6位") private String password; } ``` ## 7. 代码规范 ### 7.1 命名规范 - 组件名:使用PascalCase,如`UserManagement.vue` - 方法名:使用camelCase,如`getUsers`、`handleSortChange` - 变量名:使用camelCase,如`userList`、`selectedIds` - 常量名:使用UPPER_SNAKE_CASE,如`MAX_PAGE_SIZE` ### 7.2 注释规范 ```javascript /** * 获取用户列表 */ const getUsers = async () => { // 实现代码 } /** * 处理排序变化 * @param {Object} param - 排序参数 * @param {String} param.prop - 排序字段 * @param {String} param.order - 排序方向 */ const handleSortChange = ({ prop, order }) => { // 实现代码 } ``` ## 8. 性能优化 ### 8.1 防抖和节流 ```javascript import { debounce } from 'lodash-es' const search = debounce(() => { getUsers() }, 300) ``` ### 8.2 虚拟滚动 对于大量数据,使用虚拟滚动提高性能。 ```vue ``` ## 9. 安全规范 ### 9.1 XSS防护 使用Vue的插值表达式,避免直接使用v-html。 ```vue
{{ user.name }}
``` ### 9.2 CSRF防护 所有POST、PUT、DELETE请求都应该携带CSRF token。 ```javascript import request from '@/utils/request' request.interceptors.request.use(config => { const token = localStorage.getItem('csrf_token') if (token) { config.headers['X-CSRF-TOKEN'] = token } return config }) ``` ## 10. 可访问性 ### 10.1 语义化HTML ```vue

页面标题

...
...
...
``` ### 10.2 键盘导航 确保所有交互元素都可以通过键盘访问。 ```vue 点击 ```