优秀的用户体验设计能让产品脱颖而出。本文将系统性地介绍UX设计的核心原则、心理学基础和实践方法。

UX设计核心原则

尼尔森十大可用性原则

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
"""
尼尔森十大可用性原则(Jakob Nielsen's 10 Usability Heuristics):

┌─────────────────────────────────────────────────────────────┐
│ 1. 系统状态可见性 (Visibility of System Status)            │
│    - 始终告知用户当前发生什么                               │
│    - 提供即时反馈                                           │
├─────────────────────────────────────────────────────────────┤
│ 2. 系统与现实世界匹配 (Match Real World)                   │
│    - 使用用户熟悉的语言和概念                               │
│    - 遵循现实世界的约定                                     │
├─────────────────────────────────────────────────────────────┤
│ 3. 用户控制与自由 (User Control & Freedom)                 │
│    - 提供紧急出口                                           │
│    - 支持撤销和重做                                         │
├─────────────────────────────────────────────────────────────┤
│ 4. 一致性 (Consistency & Standards)                        │
│    - 遵循平台和行业规范                                     │
│    - 保持内部一致性                                         │
├─────────────────────────────────────────────────────────────┤
│ 5. 预防错误 (Error Prevention)                             │
│    - 优先预防而非报错                                       │
│    - 提供确认提示                                           │
├─────────────────────────────────────────────────────────────┤
│ 6. 识别而非回忆 (Recognition vs Recall)                    │
│    - 将信息显性化                                           │
│    - 减少记忆负担                                           │
├─────────────────────────────────────────────────────────────┤
│ 7. 灵活使用效率 (Flexibility & Efficiency)                 │
│    - 为新手和专家都提供便利                                 │
│    - 支持快捷操作                                           │
├─────────────────────────────────────────────────────────────┤
│ 8. 审美与简约 (Aesthetic & Minimalist Design)              │
│    - 去除无关信息                                           │
│    - 突出核心内容                                           │
├─────────────────────────────────────────────────────────────┤
│ 9. 帮助用户识别错误 (Help Users Recognize Errors)          │
│    - 用通俗语言说明错误                                     │
│    - 提供解决方案                                           │
├─────────────────────────────────────────────────────────────┤
│ 10. 帮助与文档 (Help & Documentation)                      │
│     - 提供易于搜索的帮助信息                                │
│     - 针对任务提供指导                                      │
└─────────────────────────────────────────────────────────────┘
"""

# 代码实现示例

class UXPrincipleChecker:
    """UX设计原则检查器"""

    def check_visibility(self, component: dict) -> dict:
        """
        检查系统状态可见性
        """
        checks = {
            "loading_indicator": False,
            "progress_feedback": False,
            "status_messages": False
        }

        # 检查加载状态
        if component.get("loading") is not None:
            checks["loading_indicator"] = True

        # 检查进度反馈
        if component.get("progress") is not None:
            checks["progress_feedback"] = True

        # 检查状态消息
        if component.get("status") is not None:
            checks["status_messages"] = True

        score = sum(checks.values()) / len(checks)

        return {
            "checks": checks,
            "score": score,
            "recommendations": self._get_visibility_recommendations(checks)
        }

    def _get_visibility_recommendations(self, checks: dict) -> list:
        """获取可见性改进建议"""
        recommendations = []

        if not checks["loading_indicator"]:
            recommendations.append(
                "添加加载指示器,让用户知道系统正在工作"
            )

        if not checks["progress_feedback"]:
            recommendations.append(
                "为长时间操作添加进度条或百分比显示"
            )

        if not checks["status_messages"]:
            recommendations.append(
                "为用户操作提供即时反馈消息"
            )

        return recommendations

认知心理学基础

米勒定律与信息分组

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/* 米勒定律:短期记忆只能容纳7±2个信息块 */
/* 在设计中应用:将信息分组,减少认知负担 */

/* 不好的设计:信息过载 */
.bad-design .menu-items {
    /* 15个菜单项平铺,超出短期记忆容量 */
    display: flex;
    gap: 8px;
}

/* 好的设计:信息分组 */
.good-design .menu-categories {
    /* 分为3-5个主要类别 */
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 24px;
}

.good-design .menu-category {
    /* 每个类别下最多5-7个子项 */
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    padding: 16px;
}

/* 分组示例 */
.navigation {
    display: flex;
    flex-direction: column;
    gap: 32px;  /* 组间间距大,视觉上区分分组 */
}

.navigation-group {
    display: flex;
    flex-direction: column;
    gap: 8px;   /* 组内间距小,表示关联 */
}

.navigation-group-header {
    font-weight: 600;
    color: #6b7280;
    text-transform: uppercase;
    font-size: 12px;
    letter-spacing: 0.05em;
}

菲茨定律与交互设计

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/* 菲茨定律:到达目标的时间取决于距离和目标大小 */
/* T = a + b * log2(D/W + 1) */
/* T: 时间, D: 距离, W: 目标宽度 */

/* 应用1:重要的按钮应该更大 */
.button-primary {
    padding: 12px 24px;  /* 更大的点击区域 */
    font-size: 16px;
    font-weight: 600;
}

.button-secondary {
    padding: 8px 16px;   /* 次要按钮较小 */
    font-size: 14px;
}

/* 应用2:相关元素应该靠近 */
.form-group {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.form-group input {
    /* 输入框和标签靠近,减少视线移动距离 */
    margin-top: 4px;
}

/* 应用3:可点击区域扩展 */
.icon-button {
    position: relative;
    width: 44px;  /* iOS建议最小点击目标:44x44pt */
    height: 44px;
    display: flex;
    align-items: center;
    justify_content: center;
}

.icon-button svg {
    width: 24px;
    height: 24px;
    /* 图标可能很小,但点击区域足够大 */
}

/* 应用4:菜单项设计 */
.menu-item {
    padding: 12px 16px;
    min-height: 48px;  /* Material Design建议 */
    display: flex;
    align-items: center;
    cursor: pointer;
    transition: background-color 0.2s;
}

.menu-item:hover {
    background-color: #f3f4f6;
}

.menu-item:active {
    background-color: #e5e7eb;
    /* 点击时提供视觉反馈 */
}

希克定律与决策设计

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/* 希克定律:决策时间随选项数量增加而对数增长 */
/* 减少选项可以加快决策 */

/* 不好的设计:太多选项 */
.bad-dropdown {
    /* 20+个选项让用户难以选择 */
}

/* 好的设计:渐进式披露 */
.good-dropdown {
    /* 首先显示常用选项 */
}

/* 渐进式披露实现 */
.stepped-selector {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.step-1 {
    /* 第一步:选择大类 */
}

.step-2 {
    /* 第二步:根据大类显示子选项 */
    display: none;  /* 初始隐藏 */
}

.step-2.active {
    display: block;
}

/* 示例:颜色选择器 */
.color-selector .main-colors {
    /* 首先显示10个常用颜色 */
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 8px;
}

.color-selector .more-colors {
    /* "更多"选项展开后显示所有颜色 */
    display: none;
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.3s ease-out;
}

.color-selector .more-colors.expanded {
    display: grid;
    max-height: 500px;
    grid-template-columns: repeat(10, 1fr);
    gap: 8px;
}

交互设计模式

反馈与响应

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
 * 系统反馈设计
 * 为每个用户操作提供即时反馈
 */

class InteractionFeedback {
    /**
     * 按钮点击反馈
     */
    handleButtonClick(button: HTMLElement) {
        // 1. 立即视觉反馈
        button.classList.add('active');

        // 2. 如果是耗时操作,显示加载状态
        button.dataset.loading = 'true';
        const originalText = button.textContent;
        button.innerHTML = `
            <svg class="animate-spin" viewBox="0 0 24 24">
                <!-- 加载动画 -->
            </svg>
            <span>处理中...</span>
        `;

        // 3. 执行操作
        this.executeAction().then(result => {
            // 4. 成功反馈
            button.dataset.loading = 'false';
            button.textContent = originalText;
            button.classList.remove('active');

            // 显示成功提示
            this.showToast({
                type: 'success',
                message: '操作成功',
                duration: 3000
            });
        }).catch(error => {
            // 5. 错误反馈
            button.dataset.loading = 'false';
            button.textContent = originalText;
            button.classList.remove('active');

            // 显示错误提示
            this.showToast({
                type: 'error',
                message: error.message,
                duration: 5000,
                actions: [
                    {
                        label: '重试',
                        onClick: () => this.handleButtonClick(button)
                    }
                ]
            });
        });
    }

    /**
     * 表单输入反馈
     */
    handleFormFieldInput(field: HTMLInputElement) {
        // 实时验证
        const validation = this.validateField(field);

        // 显示验证结果
        if (validation.valid) {
            field.classList.add('valid');
            field.classList.remove('invalid');
            this.showInlineMessage(field, {
                type: 'success',
                message: '格式正确'
            });
        } else {
            field.classList.add('invalid');
            field.classList.remove('valid');
            this.showInlineMessage(field, {
                type: 'error',
                message: validation.error
            });
        }
    }

    /**
     * Toast消息提示
     */
    showToast(options: {
        type: 'success' | 'error' | 'info' | 'warning',
        message: string,
        duration?: number,
        actions?: Array<{label: string, onClick: () => void}>
    }) {
        const toast = document.createElement('div');
        toast.className = `toast toast-${options.type}`;

        toast.innerHTML = `
            <div class="toast-icon">
                ${this.getIconForType(options.type)}
            </div>
            <div class="toast-message">${options.message}</div>
            ${options.actions ? `
                <div class="toast-actions">
                    ${options.actions.map(action => `
                        <button class="toast-action">${action.label}</button>
                    `).join('')}
                </div>
            ` : ''}
        `;

        document.body.appendChild(toast);

        // 自动消失
        if (options.duration) {
            setTimeout(() => {
                toast.classList.add('toast-exit');
                setTimeout(() => toast.remove(), 300);
            }, options.duration);
        }
    }
}

错误预防与处理

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
/**
 * 错误预防设计
 * 最好的错误处理是预防错误发生
 */

class ErrorPrevention {
    /**
     * 表单验证
     */
    setupFormValidation(form: HTMLFormElement) {
        // 1. 实时验证(用户输入时)
        form.querySelectorAll('input').forEach(input => {
            input.addEventListener('input', () => {
                this.validateField(input);
            });

            input.addEventListener('blur', () => {
                // 失去焦点时显示详细的验证信息
                this.showFieldErrors(input);
            });
        });

        // 2. 提交前验证
        form.addEventListener('submit', (e) => {
            const errors = this.validateForm(form);

            if (errors.length > 0) {
                e.preventDefault();

                // 高亮错误字段
                errors.forEach(error => {
                    this.highlightError(error.field, error.message);
                });

                // 显示错误摘要
                this.showFormErrors(errors);
            }
        });
    }

    /**
     * 约束输入
     */
    constrainInput(input: HTMLInputElement) {
        // 示例:密码输入
        if (input.type === 'password') {
            input.addEventListener('input', () => {
                const value = input.value;

                // 实时检查密码强度
                const strength = this.checkPasswordStrength(value);

                this.updatePasswordStrengthIndicator(strength);

                // 如果密码太弱,显示建议
                if (strength < 2) {
                    this.showPasswordSuggestions();
                }
            });
        }

        // 示例:数字输入
        if (input.type === 'number') {
            const min = parseFloat(input.min);
            const max = parseFloat(input.max);

            input.addEventListener('input', () => {
                const value = parseFloat(input.value);

                if (value < min) {
                    this.showWarning(input, `最小值是 ${min}`);
                } else if (value > max) {
                    this.showWarning(input, `最大值是 ${max}`);
                }
            });
        }
    }

    /**
     * 破坏性操作确认
     */
    setupDestructiveActionConfirmation(button: HTMLElement, action: () => void) {
        button.addEventListener('click', (e) => {
            e.preventDefault();

            // 显示确认对话框
            const confirmed = this.showConfirmDialog({
                title: '确认删除',
                message: '此操作无法撤销,确定要继续吗?',
                confirmText: '删除',
                cancelText: '取消',
                type: 'danger'
            });

            if (confirmed) {
                action();
            }
        });
    }
}

视觉设计原则

层次结构与排版

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/**
 * 视觉层次结构
 * 通过大小、颜色、位置建立清晰的层次
 */

/* 标题层次 */
h1 {
    font-size: 2.5rem;      /* 40px */
    font-weight: 700;
    line-height: 1.2;
    margin-bottom: 1rem;
}

h2 {
    font-size: 2rem;        /* 32px */
    font-weight: 600;
    line-height: 1.3;
    margin-bottom: 0.875rem;
}

h3 {
    font-size: 1.5rem;      /* 24px */
    font-weight: 600;
    line-height: 1.4;
    margin-bottom: 0.75rem;
}

h4 {
    font-size: 1.25rem;     /* 20px */
    font-weight: 600;
    line-height: 1.4;
    margin-bottom: 0.5rem;
}

/* 文本层次 */
.text-large {
    font-size: 1.125rem;    /* 18px */
    line-height: 1.5;
}

.text-body {
    font-size: 1rem;        /* 16px */
    line-height: 1.5;
}

.text-small {
    font-size: 0.875rem;    /* 14px */
    line-height: 1.5;
}

.text-caption {
    font-size: 0.75rem;     /* 12px */
    line-height: 1.4;
}

/* 颜色层次 */
.text-primary {
    color: #111827;     /* 主要文本 */
}

.text-secondary {
    color: #6b7280;     /* 次要文本 */
}

.text-tertiary {
    color: #9ca3af;     /* 辅助文本 */
}

/* 强调 */
.text-accent {
    color: #3b82f6;     /* 强调色 */
}

.text-error {
    color: #ef4444;     /* 错误 */
}

.text-success {
    color: #10b981;     /* 成功 */
}

/* 间距层次 - 使用8px基准 */
.spacing-xs { margin: 4px; }      /* 0.25rem */
.spacing-sm { margin: 8px; }      /* 0.5rem */
.spacing-md { margin: 16px; }     /* 1rem */
.spacing-lg { margin: 24px; }     /* 1.5rem */
.spacing-xl { margin: 32px; }     /* 2rem */
.spacing-2xl { margin: 48px; }    /* 3rem */

一致性设计系统

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/**
 * 设计系统
 * 保持产品的一致性
 */

interface DesignTokens {
    colors: {
        primary: {
            50: string;
            100: string;
            200: string;
            300: string;
            400: string;
            500: string;
            600: string;
            700: string;
            800: string;
            900: string;
        };
        neutral: {
            [key: string]: string;
        };
        semantic: {
            success: string;
            warning: string;
            error: string;
            info: string;
        };
    };
    spacing: {
        [key: string]: number | string;
    };
    typography: {
        fontFamily: {
            sans: string[];
            mono: string[];
        };
        fontSize: {
            [key: string]: string;
        };
        fontWeight: {
            [key: string]: number;
        };
        lineHeight: {
            [key: string]: number;
        };
    };
    borderRadius: {
        [key: string]: string;
    };
    shadows: {
        [key: string]: string;
    };
}

// 设计Token示例
const designTokens: DesignTokens = {
    colors: {
        primary: {
            50: '#eff6ff',
            100: '#dbeafe',
            200: '#bfdbfe',
            300: '#93c5fd',
            400: '#60a5fa',
            500: '#3b82f6',
            600: '#2563eb',
            700: '#1d4ed8',
            800: '#1e40af',
            900: '#1e3a8a',
        },
        neutral: {
            50: '#f9fafb',
            100: '#f3f4f6',
            200: '#e5e7eb',
            300: '#d1d5db',
            400: '#9ca3af',
            500: '#6b7280',
            600: '#4b5563',
            700: '#374151',
            800: '#1f2937',
            900: '#111827',
        },
        semantic: {
            success: '#10b981',
            warning: '#f59e0b',
            error: '#ef4444',
            info: '#3b82f6',
        }
    },
    spacing: {
        '0': '0',
        'px': '1px',
        '0.5': '2px',
        '1': '4px',
        '2': '8px',
        '3': '12px',
        '4': '16px',
        '5': '20px',
        '6': '24px',
        '8': '32px',
        '10': '40px',
        '12': '48px',
        '16': '64px',
        '20': '80px',
        '24': '96px',
    },
    typography: {
        fontFamily: {
            sans: ['Inter', 'system-ui', 'sans-serif'],
            mono: ['Fira Code', 'Monaco', 'monospace'],
        },
        fontSize: {
            'xs': '0.75rem',
            'sm': '0.875rem',
            'base': '1rem',
            'lg': '1.125rem',
            'xl': '1.25rem',
            '2xl': '1.5rem',
            '3xl': '1.875rem',
            '4xl': '2.25rem',
            '5xl': '3rem',
        },
        fontWeight: {
            'light': 300,
            'normal': 400,
            'medium': 500,
            'semibold': 600,
            'bold': 700,
        },
        lineHeight: {
            'none': 1,
            'tight': 1.25,
            'normal': 1.5,
            'relaxed': 1.75,
        }
    },
    borderRadius: {
        'none': '0',
        'sm': '0.125rem',
        'DEFAULT': '0.25rem',
        'md': '0.375rem',
        'lg': '0.5rem',
        'xl': '0.75rem',
        '2xl': '1rem',
        '3xl': '1.5rem',
        'full': '9999px',
    },
    shadows: {
        'sm': '0 1px 2px 0 rgb(0 0 0 / 0.05)',
        'DEFAULT': '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',
        'md': '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)',
        'lg': '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)',
        'xl': '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)',
    }
};

移动端UX设计

触摸友好设计

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
 * 移动端触摸设计
 * iOS最小触摸目标:44x44 pt
 * Android最小触摸目标:48x48 dp
 */

/* 触摸目标尺寸 */
.touch-target {
    min-width: 44px;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* 按钮组 */
.button-group {
    display: flex;
    gap: 12px;
}

.button-group .button {
    min-height: 48px;
    padding: 0 24px;
}

/* 列表项 */
.list-item {
    min-height: 48px;
    padding: 12px 16px;
    display: flex;
    align-items: center;
    position: relative;
}

/* 点击反馈 */
.touch-feedback {
    transition: background-color 0.2s, transform 0.1s;
}

.touch-feedback:active {
    background-color: rgba(0, 0, 0, 0.1);
    transform: scale(0.98);
}

/* 手势支持 */
.swipeable {
    touch-action: pan-y;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
}

.swipeable-item {
    scroll-snap-align: center;
    flex-shrink: 0;
}

移动端导航

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
 * 移动端导航模式
 */

class MobileNavigation {
    /**
     * 底部标签栏导航
     */
    setupBottomNavigation(nav: HTMLElement) {
        const items = nav.querySelectorAll('.nav-item');

        items.forEach(item => {
            item.addEventListener('click', () => {
                // 移除所有active状态
                items.forEach(i => i.classList.remove('active'));

                // 添加active状态
                item.classList.add('active');

                // 触发震动反馈
                if (navigator.vibrate) {
                    navigator.vibrate(10);
                }
            });
        });
    }

    /**
     * 汉堡菜单
     */
    setupHamburgerMenu(button: HTMLElement, menu: HTMLElement) {
        let isMenuOpen = false;

        button.addEventListener('click', () => {
            isMenuOpen = !isMenuOpen;

            if (isMenuOpen) {
                menu.classList.add('open');
                document.body.style.overflow = 'hidden';  // 防止背景滚动
            } else {
                menu.classList.remove('open');
                document.body.style.overflow = '';
            }
        });

        // 点击菜单外部关闭
        document.addEventListener('click', (e) => {
            if (isMenuOpen &&
                !menu.contains(e.target as Node) &&
                !button.contains(e.target as Node)) {
                isMenuOpen = false;
                menu.classList.remove('open');
                document.body.style.overflow = '';
            }
        });
    }
}

总结

优秀用户体验设计的核心要素:

  1. 以用户为中心:始终从用户角度思考
  2. 一致性:保持视觉和交互的一致性
  3. 反馈及时:每个操作都有明确反馈
  4. 预防错误:设计要预防而非补救
  5. 简洁高效:减少用户认知负担
  6. 可访问性:确保所有人都能使用
  7. 美观愉悦:创造情感连接

UX设计是持续的优化过程,需要通过用户研究和数据分析不断改进。