什么是按钮?为什么需要统一的术语

在网页与 App 界面里,按钮(Button)是用户触发动作最直接的入口:提交表单、确认删除、切换状态、打开菜单……几乎所有交互都绕不开它。但同一个「按钮」在不同设计系统里叫法不一——主按钮、Primary、CTA、行动点……概念混乱会让设计与开发反复扯皮。

这篇文章把常见的网页按钮按视觉权重交互行为拆成 13 类,并做成一个可直接点击把玩的「按钮操场」。你可以把下方演示当成一份活的设计规范:看样式、点交互、读源码。

13 种常见按钮一览

下面这张卡片汇集了 13 种常用按钮类型:从主 / 次 / 文字按钮,到幽灵、图标、FAB、开关、分段、下拉、加载、禁用等状态与特殊样式。点击任意按钮,右下角的操作反馈区会实时显示你触发了什么。

按钮操场交互演示
<div class="container">
        <h2 class="section-title">① 主要按钮 <span>Primary</span></h2>
        <p class="section-desc">页面中最突出的行动号召,用于最重要的操作(如提交、确认、购买)。</p>
        <div class="btn-grid">
            <div class="btn-item">
                <button class="btn btn-primary" data-action="primary">主按钮</button>
                <span class="label">Primary</span>
            </div>
            <div class="btn-item">
                <button class="btn btn-secondary" data-action="secondary">次按钮</button>
                <span class="label">Secondary</span>
            </div>
            <div class="btn-item">
                <button class="btn btn-tertiary" data-action="tertiary">第三按钮</button>
                <span class="label">Tertiary</span>
            </div>
            <div class="btn-item">
                <button class="btn btn-danger" data-action="danger">危险按钮</button>
                <span class="label">Danger</span>
            </div>
        </div>

        <!-- ===== 2. 特殊样式 ===== -->
        <h2 class="section-title">② 特殊样式 <span>Style</span></h2>
        <p class="section-desc">适用于不同视觉场景的按钮变体。</p>
        <div class="btn-grid">
            <div class="btn-item">
                <button class="btn btn-ghost" data-action="ghost">幽灵按钮</button>
                <span class="label">Ghost</span>
            </div>
            <div class="btn-item">
                <button class="btn btn-icon" data-action="icon" aria-label="搜索">
                    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
                </button>
                <span class="label">Icon <span class="note">(搜索)</span></span>
            </div>
            <div class="btn-item">
                <button class="btn btn-icon" data-action="icon-heart" aria-label="收藏">
                    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>
                </button>
                <span class="label">Icon <span class="note">(收藏)</span></span>
            </div>
            <div class="btn-item">
                <button class="btn btn-fab" data-action="fab" aria-label="添加">
                    <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
                </button>
                <span class="label">FAB <span class="note">(浮动)</span></span>
            </div>
        </div>

        <!-- ===== 3. 状态按钮 ===== -->
        <h2 class="section-title">③ 状态与交互 <span>State</span></h2>
        <p class="section-desc">带有状态切换、加载、下拉菜单等交互行为的按钮。</p>

        <div class="btn-grid" style="flex-wrap: wrap; gap: 30px 48px;">

            <!-- 开关 -->
            <div class="btn-item">
                <button class="btn-toggle" data-action="toggle" aria-label="开关">
                    <span class="toggle-knob"></span>
                </button>
                <span class="label">Toggle <span class="note">(开关)</span></span>
            </div>

            <!-- 分段 -->
            <div class="btn-item">
                <div class="btn-segmented" data-action="segmented">
                    <button class="seg-item active" data-value="list">列表</button>
                    <button class="seg-item" data-value="grid">网格</button>
                    <button class="seg-item" data-value="card">卡片</button>
                </div>
                <span class="label">Segmented <span class="note">(分段)</span></span>
            </div>

            <!-- 下拉 -->
            <div class="btn-item">
                <div class="btn-dropdown">
                    <button class="btn btn-secondary" data-action="dropdown">
                        操作 <span class="arrow">▼</span>
                    </button>
                    <ul class="dropdown-menu">
                        <li data-value="edit"><span class="label-icon">✎</span> 编辑</li>
                        <li data-value="duplicate"><span class="label-icon">⊞</span> 复制</li>
                        <li class="divider"></li>
                        <li data-value="delete" style="color:#dc2626;"><span class="label-icon">✕</span> 删除</li>
                    </ul>
                </div>
                <span class="label">Dropdown <span class="note">(下拉)</span></span>
            </div>

            <!-- 加载 -->
            <div class="btn-item">
                <button class="btn btn-primary btn-loading" data-action="loading">
                    <span class="loader"></span>
                    <span class="btn-text">提交</span>
                </button>
                <span class="label">Loading <span class="note">(加载)</span></span>
            </div>

            <!-- 禁用 -->
            <div class="btn-item">
                <button class="btn btn-secondary btn-disabled" data-action="disabled" disabled>
                    禁用状态
                </button>
                <span class="label">Disabled <span class="note">(禁用)</span></span>
            </div>

        </div>

        <!-- ===== 4. 文字按钮 ===== -->
        <h2 class="section-title">④ 文字按钮 <span>Text</span></h2>
        <p class="section-desc">最轻量的按钮形式,常用于辅助操作或链接样式。</p>
        <div class="btn-grid" style="gap: 12px 28px;">
            <div class="btn-item" style="flex-direction:row; gap:12px;">
                <button class="btn btn-tertiary" data-action="text-cancel" style="font-size:0.9rem;">取消</button>
                <button class="btn btn-tertiary" data-action="text-confirm" style="font-size:0.9rem; color:#2563eb; font-weight:600;">确认</button>
                <button class="btn btn-tertiary" data-action="text-learn" style="font-size:0.9rem; color:#2563eb;">
                    了解更多 →
                </button>
                <span class="label" style="margin-left:4px;">Text Button</span>
            </div>
        </div>

        <!-- ===== 交互反馈区 ===== -->
        <div class="feedback-area">
            <span class="fb-label">操作反馈</span>
            <div class="fb-log" id="feedbackLog">
                点击任意按钮,此处显示交互信息…
            </div>
            <button class="btn btn-secondary" id="clearLog" style="padding:6px 16px; min-height:36px; font-size:0.8rem; flex-shrink:0;">
                清空
            </button>
        </div>

        <!-- ===== 场景示例 ===== -->
        <div class="scene-example">
            <h3>场景组合示例 — 对话框 / 表单底部</h3>
            <div class="scene-buttons">
                <span class="scene-label">操作:</span>
                <button class="btn btn-secondary" data-action="scene-cancel" style="min-width:80px;">取消</button>
                <button class="btn btn-danger" data-action="scene-delete" style="min-width:80px;">删除</button>
                <button class="btn btn-primary" data-action="scene-confirm" style="min-width:100px;">确认提交</button>
            </div>
            <div style="margin-top:16px; display:flex; flex-wrap:wrap; gap:12px; align-items:center;">
                <span class="scene-label">工具栏:</span>
                <button class="btn btn-icon" data-action="toolbar-edit" aria-label="编辑">
                    <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
                </button>
                <button class="btn btn-icon" data-action="toolbar-download" aria-label="下载">
                    <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
                </button>
                <button class="btn btn-secondary" data-action="toolbar-save" style="padding:6px 18px; min-height:36px; font-size:0.85rem;">保存</button>
            </div>
        </div>
    </div>
/* ===== 全局重置 & 基础 ===== */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
            background: #f8fafc;
            color: #1e293b;
            padding: 40px 20px;
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .container {
            max-width: 1200px;
            width: 100%;
            background: #ffffff;
            border-radius: 32px;
            box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.15);
            padding: 48px 40px 56px;
        }

        /* ===== 标题区 ===== */
        .page-header {
            margin-bottom: 48px;
            border-bottom: 2px solid #f1f5f9;
            padding-bottom: 28px;
        }

        .page-header h1 {
            font-size: 2rem;
            font-weight: 700;
            letter-spacing: -0.02em;
            background: linear-gradient(135deg, #0f172a, #3b82f6);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
            margin-bottom: 8px;
        }

        .page-header p {
            color: #64748b;
            font-size: 1.05rem;
            max-width: 680px;
        }

        .badge {
            display: inline-block;
            background: #eef2ff;
            color: #4338ca;
            font-size: 0.75rem;
            font-weight: 600;
            padding: 4px 14px;
            border-radius: 100px;
            letter-spacing: 0.3px;
            margin-top: 8px;
        }

        /* ===== 分组标题 ===== */
        .section-title {
            font-size: 1.25rem;
            font-weight: 600;
            margin: 40px 0 20px 0;
            display: flex;
            align-items: center;
            gap: 12px;
        }

        .section-title span {
            background: #e2e8f0;
            color: #475569;
            font-size: 0.7rem;
            font-weight: 700;
            padding: 2px 12px;
            border-radius: 100px;
            letter-spacing: 0.5px;
        }

        .section-desc {
            color: #64748b;
            font-size: 0.95rem;
            margin-bottom: 20px;
        }

        /* ===== 按钮网格 ===== */
        .btn-grid {
            display: flex;
            flex-wrap: wrap;
            gap: 24px 40px;
            align-items: center;
            padding: 16px 0 8px 0;
        }

        .btn-grid.column {
            flex-direction: column;
            align-items: flex-start;
            gap: 16px;
        }

        .btn-item {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 8px;
            min-width: 100px;
        }

        .btn-item .label {
            font-size: 0.75rem;
            font-weight: 500;
            color: #64748b;
            letter-spacing: 0.2px;
            text-align: center;
        }

        .btn-item .label .note {
            font-weight: 400;
            color: #94a3b8;
            font-size: 0.7rem;
        }

        /* ===== 基础按钮样式 ===== */
        .btn {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            font-family: inherit;
            font-size: 0.95rem;
            font-weight: 500;
            padding: 10px 24px;
            border-radius: 10px;
            border: 2px solid transparent;
            cursor: pointer;
            transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
            text-decoration: none;
            white-space: nowrap;
            user-select: none;
            position: relative;
            outline: none;
            min-height: 48px;
            min-width: 80px;
            background: transparent;
            color: #1e293b;
        }

        .btn:focus-visible {
            box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.3);
        }

        /* 点击波纹 */
        .btn .ripple {
            position: absolute;
            border-radius: 50%;
            background: rgba(255, 255, 255, 0.35);
            transform: scale(0);
            animation: rippleAnim 0.6s linear;
            pointer-events: none;
        }

        .btn-dark .ripple {
            background: rgba(255, 255, 255, 0.25);
        }

        @keyframes rippleAnim {
            to {
                transform: scale(4);
                opacity: 0;
            }
        }

        /* ===== 按钮变体 ===== */

        /* 主按钮 */
        .btn-primary {
            background: #2563eb;
            color: #fff;
            border-color: #2563eb;
        }
        .btn-primary:hover {
            background: #1d4ed8;
            border-color: #1d4ed8;
            transform: translateY(-1px);
            box-shadow: 0 8px 20px -6px rgba(37, 99, 235, 0.35);
        }
        .btn-primary:active {
            transform: scale(0.97);
        }

        /* 次按钮 */
        .btn-secondary {
            background: #fff;
            color: #1e293b;
            border-color: #cbd5e1;
        }
        .btn-secondary:hover {
            background: #f8fafc;
            border-color: #94a3b8;
        }
        .btn-secondary:active {
            transform: scale(0.97);
        }

        /* 第三按钮 (文字按钮) */
        .btn-tertiary {
            background: transparent;
            color: #475569;
            border-color: transparent;
            padding: 10px 16px;
            min-width: auto;
        }
        .btn-tertiary:hover {
            background: #f1f5f9;
            color: #0f172a;
        }
        .btn-tertiary:active {
            transform: scale(0.97);
        }

        /* 危险按钮 */
        .btn-danger {
            background: #dc2626;
            color: #fff;
            border-color: #dc2626;
        }
        .btn-danger:hover {
            background: #b91c1c;
            border-color: #b91c1c;
            box-shadow: 0 8px 20px -6px rgba(220, 38, 38, 0.35);
            transform: translateY(-1px);
        }
        .btn-danger:active {
            transform: scale(0.97);
        }

        /* 幽灵按钮 */
        .btn-ghost {
            background: transparent;
            color: #2563eb;
            border-color: #2563eb;
        }
        .btn-ghost:hover {
            background: #eff6ff;
            border-color: #1d4ed8;
        }
        .btn-ghost:active {
            transform: scale(0.97);
        }

        /* 图标按钮 */
        .btn-icon {
            background: transparent;
            color: #475569;
            border-color: transparent;
            padding: 10px 12px;
            min-width: auto;
            border-radius: 10px;
            font-size: 1.2rem;
        }
        .btn-icon:hover {
            background: #f1f5f9;
            color: #0f172a;
        }
        .btn-icon:active {
            transform: scale(0.92);
        }

        /* 浮动按钮 (FAB) */
        .btn-fab {
            background: #2563eb;
            color: #fff;
            border-color: #2563eb;
            border-radius: 9999px;
            width: 56px;
            height: 56px;
            padding: 0;
            min-width: auto;
            font-size: 1.5rem;
            box-shadow: 0 8px 24px rgba(37, 99, 235, 0.3);
        }
        .btn-fab:hover {
            background: #1d4ed8;
            border-color: #1d4ed8;
            transform: translateY(-2px) scale(1.02);
            box-shadow: 0 12px 32px -8px rgba(37, 99, 235, 0.4);
        }
        .btn-fab:active {
            transform: scale(0.94);
        }

        /* ===== 开关按钮 ===== */
        .btn-toggle {
            background: #e2e8f0;
            border: none;
            border-radius: 9999px;
            width: 52px;
            height: 28px;
            padding: 0;
            min-width: auto;
            cursor: pointer;
            position: relative;
            transition: background 0.25s ease;
            flex-shrink: 0;
        }
        .btn-toggle .toggle-knob {
            display: block;
            width: 22px;
            height: 22px;
            background: #fff;
            border-radius: 50%;
            position: absolute;
            top: 3px;
            left: 3px;
            transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
            box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
        }
        .btn-toggle.active {
            background: #2563eb;
        }
        .btn-toggle.active .toggle-knob {
            transform: translateX(24px);
        }
        .btn-toggle:hover {
            opacity: 0.85;
        }
        .btn-toggle:active .toggle-knob {
            transform: scale(0.92);
        }
        .btn-toggle.active:active .toggle-knob {
            transform: translateX(24px) scale(0.92);
        }

        /* ===== 下拉按钮 ===== */
        .btn-dropdown {
            position: relative;
        }
        .btn-dropdown .dropdown-menu {
            position: absolute;
            top: calc(100% + 8px);
            left: 0;
            min-width: 180px;
            background: #fff;
            border-radius: 12px;
            box-shadow: 0 16px 48px -12px rgba(0, 0, 0, 0.2);
            border: 1px solid #e2e8f0;
            padding: 6px 0;
            opacity: 0;
            visibility: hidden;
            transform: translateY(-8px) scale(0.96);
            transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
            z-index: 100;
            list-style: none;
        }
        .btn-dropdown .dropdown-menu.open {
            opacity: 1;
            visibility: visible;
            transform: translateY(0) scale(1);
        }
        .btn-dropdown .dropdown-menu li {
            padding: 10px 20px;
            font-size: 0.9rem;
            color: #1e293b;
            cursor: pointer;
            transition: background 0.15s;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .btn-dropdown .dropdown-menu li:hover {
            background: #f1f5f9;
        }
        .btn-dropdown .dropdown-menu li:active {
            background: #e2e8f0;
        }
        .btn-dropdown .dropdown-menu .divider {
            height: 1px;
            background: #e2e8f0;
            margin: 4px 12px;
            padding: 0;
        }
        .btn-dropdown .dropdown-menu .label-icon {
            font-size: 1rem;
            width: 20px;
            text-align: center;
        }
        .btn-dropdown .arrow {
            font-size: 0.7rem;
            transition: transform 0.2s;
            margin-left: 4px;
        }
        .btn-dropdown .arrow.open {
            transform: rotate(180deg);
        }

        /* ===== 分段按钮 ===== */
        .btn-segmented {
            display: inline-flex;
            background: #f1f5f9;
            border-radius: 10px;
            padding: 4px;
            gap: 4px;
            border: 1px solid #e2e8f0;
        }
        .btn-segmented .seg-item {
            padding: 8px 20px;
            border-radius: 8px;
            font-size: 0.9rem;
            font-weight: 500;
            color: #64748b;
            cursor: pointer;
            transition: all 0.2s;
            border: none;
            background: transparent;
            font-family: inherit;
            white-space: nowrap;
        }
        .btn-segmented .seg-item:hover {
            color: #0f172a;
        }
        .btn-segmented .seg-item.active {
            background: #fff;
            color: #1e293b;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
        }
        .btn-segmented .seg-item:active {
            transform: scale(0.95);
        }

        /* ===== 加载按钮 ===== */
        .btn-loading {
            position: relative;
        }
        .btn-loading .loader {
            display: none;
            width: 20px;
            height: 20px;
            border: 2.5px solid rgba(255, 255, 255, 0.3);
            border-top-color: #fff;
            border-radius: 50%;
            animation: spin 0.7s linear infinite;
        }
        .btn-loading.loading .loader {
            display: inline-block;
        }
        .btn-loading.loading .btn-text {
            visibility: hidden;
            opacity: 0;
            width: 0;
            display: inline-block;
            overflow: hidden;
        }
        .btn-loading.loading {
            gap: 0;
            padding: 10px 20px;
        }
        .btn-loading.loading .loader {
            margin: 0 2px;
        }

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

        /* ===== 禁用按钮 ===== */
        .btn-disabled {
            opacity: 0.5;
            pointer-events: none;
            cursor: not-allowed;
            filter: grayscale(0.2);
        }

        /* ===== 交互反馈区 ===== */
        .feedback-area {
            margin-top: 40px;
            padding: 24px 28px;
            background: #f8fafc;
            border-radius: 16px;
            border: 1px solid #e2e8f0;
            display: flex;
            align-items: center;
            gap: 20px;
            flex-wrap: wrap;
        }
        .feedback-area .fb-label {
            font-size: 0.9rem;
            font-weight: 500;
            color: #475569;
            min-width: 100px;
        }
        .feedback-area .fb-log {
            font-size: 0.9rem;
            color: #1e293b;
            background: #fff;
            padding: 8px 18px;
            border-radius: 8px;
            border: 1px solid #e2e8f0;
            min-height: 44px;
            display: flex;
            align-items: center;
            flex: 1;
            min-width: 200px;
            font-family: 'SF Mono', 'Fira Code', monospace;
            font-size: 0.85rem;
        }
        .feedback-area .fb-log .highlight {
            color: #2563eb;
            font-weight: 600;
        }

        /* ===== 场景示例 ===== */
        .scene-example {
            margin-top: 48px;
            padding: 28px 32px;
            background: #f1f5f9;
            border-radius: 16px;
            border: 1px solid #e2e8f0;
        }
        .scene-example h3 {
            font-size: 1rem;
            font-weight: 600;
            margin-bottom: 16px;
            color: #0f172a;
        }
        .scene-example .scene-buttons {
            display: flex;
            flex-wrap: wrap;
            gap: 12px;
            align-items: center;
        }
        .scene-example .scene-label {
            font-size: 0.8rem;
            color: #64748b;
            font-weight: 500;
            margin-right: 8px;
        }

        /* ===== 响应式 ===== */
        @media (max-width: 720px) {
            .container {
                padding: 28px 18px 36px;
            }
            .page-header h1 {
                font-size: 1.5rem;
            }
            .btn-grid {
                gap: 16px 24px;
            }
            .btn {
                font-size: 0.85rem;
                padding: 8px 18px;
                min-height: 42px;
                min-width: 64px;
            }
            .btn-fab {
                width: 48px;
                height: 48px;
                font-size: 1.2rem;
            }
            .feedback-area {
                flex-direction: column;
                align-items: stretch;
            }
            .feedback-area .fb-label {
                min-width: auto;
            }
            .btn-segmented .seg-item {
                padding: 6px 14px;
                font-size: 0.8rem;
            }
            .scene-example {
                padding: 20px 16px;
            }
        }

        @media (max-width: 480px) {
            body {
                padding: 16px 8px;
            }
            .container {
                padding: 20px 12px 28px;
                border-radius: 20px;
            }
            .btn-grid {
                gap: 12px 16px;
                justify-content: center;
            }
            .btn-item {
                min-width: 70px;
            }
            .btn {
                font-size: 0.8rem;
                padding: 6px 14px;
                min-height: 36px;
                min-width: 56px;
                border-radius: 8px;
            }
            .btn-fab {
                width: 44px;
                height: 44px;
                font-size: 1.1rem;
            }
            .btn-toggle {
                width: 44px;
                height: 24px;
            }
            .btn-toggle .toggle-knob {
                width: 18px;
                height: 18px;
                top: 3px;
                left: 3px;
            }
            .btn-toggle.active .toggle-knob {
                transform: translateX(20px);
            }
            .btn-dropdown .dropdown-menu {
                min-width: 150px;
                left: -8px;
            }
            .btn-dropdown .dropdown-menu li {
                padding: 8px 16px;
                font-size: 0.8rem;
            }
            .feedback-area .fb-log {
                font-size: 0.75rem;
                min-height: 36px;
                padding: 6px 14px;
            }
        }

        /* ===== 工具类 ===== */
        .mt-8 {
            margin-top: 8px;
        }
        .mt-16 {
            margin-top: 16px;
        }
        .flex-center {
            display: flex;
            align-items: center;
            gap: 12px;
            flex-wrap: wrap;
        }
        .gap-8 {
            gap: 8px;
        }
        .gap-4 {
            gap: 4px;
        }

        /* 自定义滚动 */
        ::-webkit-scrollbar {
            width: 6px;
            height: 6px;
        }
        ::-webkit-scrollbar-track {
            background: #f1f5f9;
        }
        ::-webkit-scrollbar-thumb {
            background: #cbd5e1;
            border-radius: 100px;
        }
        ::-webkit-scrollbar-thumb:hover {
            background: #94a3b8;
        }
(function() {
            'use strict';

            const log = document.getElementById('feedbackLog');

            function writeLog(msg, type) {
                const now = new Date();
                const time = now.toLocaleTimeString('zh-CN', { hour12: false });
                const icon = type === 'action' ? '⚡' :
                    type === 'toggle' ? '🔄' :
                    type === 'seg' ? '📐' :
                    type === 'dropdown' ? '📂' :
                    type === 'loading' ? '⏳' : '📌';
                log.innerHTML = `<span style="color:#94a3b8;font-weight:400;">${time}</span> ${icon} ${msg}`;
            }

            // ---- 波纹效果 ----
            function createRipple(e, btn) {
                const rect = btn.getBoundingClientRect();
                const size = Math.max(rect.width, rect.height) * 0.6;
                const x = (e.clientX || e.touches?.[0]?.clientX || rect.left + rect.width / 2) - rect.left - size / 2;
                const y = (e.clientY || e.touches?.[0]?.clientY || rect.top + rect.height / 2) - rect.top - size / 2;
                const ripple = document.createElement('span');
                ripple.className = 'ripple';
                ripple.style.width = ripple.style.height = size + 'px';
                ripple.style.left = x + 'px';
                ripple.style.top = y + 'px';
                btn.style.overflow = 'hidden';
                btn.appendChild(ripple);
                setTimeout(() => ripple.remove(), 600);
            }

            // ---- 通用点击处理 ----
            document.addEventListener('click', function(e) {
                const btn = e.target.closest('.btn, .btn-toggle, .seg-item, .btn-dropdown .dropdown-menu li');
                if (!btn) return;

                // 禁用按钮不处理
                if (btn.classList.contains('btn-disabled') || btn.disabled) {
                    writeLog('⛔ 按钮处于禁用状态,无法交互', 'action');
                    return;
                }

                // ---- 开关 ----
                if (btn.classList.contains('btn-toggle')) {
                    e.preventDefault();
                    btn.classList.toggle('active');
                    const state = btn.classList.contains('active') ? '开启' : '关闭';
                    writeLog(`开关切换为 <span class="highlight">${state}</span>`, 'toggle');
                    createRipple(e, btn);
                    return;
                }

                // ---- 分段按钮 ----
                if (btn.classList.contains('seg-item')) {
                    const parent = btn.closest('.btn-segmented');
                    if (!parent) return;
                    parent.querySelectorAll('.seg-item').forEach(item => item.classList.remove('active'));
                    btn.classList.add('active');
                    const val = btn.dataset.value || btn.textContent.trim();
                    writeLog(`视图切换为 <span class="highlight">${val}</span>`, 'seg');
                    createRipple(e, btn);
                    return;
                }

                // ---- 下拉菜单项 ----
                if (btn.closest('.dropdown-menu')) {
                    const menu = btn.closest('.dropdown-menu');
                    const container = menu.closest('.btn-dropdown');
                    const trigger = container?.querySelector('.btn');
                    const val = btn.dataset.value || btn.textContent.trim();
                    writeLog(`下拉选择 <span class="highlight">${val}</span>`, 'dropdown');
                    menu.classList.remove('open');
                    if (trigger) {
                        const arrow = trigger.querySelector('.arrow');
                        if (arrow) arrow.classList.remove('open');
                    }
                    createRipple(e, btn);
                    return;
                }

                // ---- 下拉触发器 ----
                if (btn.dataset.action === 'dropdown') {
                    const container = btn.closest('.btn-dropdown');
                    if (!container) return;
                    const menu = container.querySelector('.dropdown-menu');
                    const arrow = btn.querySelector('.arrow');
                    if (!menu) return;
                    const isOpen = menu.classList.contains('open');
                    // 关闭所有其他下拉
                    document.querySelectorAll('.btn-dropdown .dropdown-menu.open').forEach(m => {
                        if (m !== menu) {
                            m.classList.remove('open');
                            const trig = m.closest('.btn-dropdown')?.querySelector('.btn');
                            const a = trig?.querySelector('.arrow');
                            if (a) a.classList.remove('open');
                        }
                    });
                    if (isOpen) {
                        menu.classList.remove('open');
                        if (arrow) arrow.classList.remove('open');
                    } else {
                        menu.classList.add('open');
                        if (arrow) arrow.classList.add('open');
                    }
                    createRipple(e, btn);
                    return;
                }

                // ---- 加载按钮 ----
                if (btn.dataset.action === 'loading') {
                    if (btn.classList.contains('loading')) return;
                    btn.classList.add('loading');
                    writeLog('⏳ 加载中...', 'loading');
                    createRipple(e, btn);
                    setTimeout(() => {
                        btn.classList.remove('loading');
                        writeLog('✅ 加载完成', 'loading');
                    }, 2000);
                    return;
                }

                // ---- 其他所有按钮 ----
                const action = btn.dataset.action || 'button';
                const label = btn.textContent.trim().slice(0, 20) || action;
                writeLog(`点击 <span class="highlight">${label}</span> (${action})`, 'action');
                createRipple(e, btn);

                // 特定动作的额外反馈
                if (action === 'scene-confirm') {
                    writeLog('✅ 表单已提交', 'action');
                }
                if (action === 'scene-delete') {
                    writeLog('🗑️ 删除操作已触发 (演示)', 'action');
                }
                if (action === 'scene-cancel') {
                    writeLog('✖️ 已取消', 'action');
                }
                if (action === 'text-confirm') {
                    writeLog('✅ 确认操作', 'action');
                }
                if (action === 'text-cancel') {
                    writeLog('✖️ 已取消', 'action');
                }
                if (action === 'text-learn') {
                    writeLog('📖 了解更多', 'action');
                }
                if (action === 'fab') {
                    writeLog('➕ 浮动操作按钮 (FAB)', 'action');
                }
                if (action === 'icon' || action === 'icon-heart') {
                    const name = action === 'icon' ? '搜索' : '收藏';
                    writeLog(`❤️ 图标按钮 — ${name}`, 'action');
                }
                if (action === 'toolbar-edit') {
                    writeLog('✎ 编辑模式', 'action');
                }
                if (action === 'toolbar-download') {
                    writeLog('⬇️ 下载开始', 'action');
                }
                if (action === 'toolbar-save') {
                    writeLog('💾 已保存', 'action');
                }
            });

            // ---- 点击外部关闭下拉 ----
            document.addEventListener('click', function(e) {
                if (!e.target.closest('.btn-dropdown')) {
                    document.querySelectorAll('.btn-dropdown .dropdown-menu.open').forEach(menu => {
                        menu.classList.remove('open');
                        const trig = menu.closest('.btn-dropdown')?.querySelector('.btn');
                        const arrow = trig?.querySelector('.arrow');
                        if (arrow) arrow.classList.remove('open');
                    });
                }
            });

            // ---- 清空日志 ----
            document.getElementById('clearLog').addEventListener('click', function(e) {
                log.innerHTML = '日志已清空';
                createRipple(e, this);
            });

            // ---- 键盘支持:Enter/Space 触发按钮 ----
            document.addEventListener('keydown', function(e) {
                if (e.key === 'Enter' || e.key === ' ') {
                    const target = e.target;
                    if (target.closest && target.closest('.btn, .btn-toggle, .seg-item')) {
                        const btn = target.closest('.btn, .btn-toggle, .seg-item');
                        if (btn && !btn.disabled && !btn.classList.contains('btn-disabled')) {
                            // 模拟点击
                            btn.click();
                            e.preventDefault();
                        }
                    }
                }
            });

            // ---- 初始提示 ----
            setTimeout(() => {
                writeLog('点击任意按钮体验交互反馈', 'action');
            }, 300);

        })();

怎么选按钮

  • 主按钮(Primary):一屏只放一个,承载页面最重要的动作,比如「确认提交」。
  • 次按钮(Secondary):与主按钮搭配,做次要或取消操作。
  • 文字按钮(Text):最轻量,用于辅助链接式操作,如「了解更多」。
  • 危险按钮(Danger):删除、退出等不可逆动作,用红色强化警示。
  • 幽灵 / 图标 / FAB:在空间紧张或移动端用图标、浮动按钮替代文字。
  • 开关 / 分段 / 下拉 / 加载 / 禁用:表达状态与交互过程,注意加载与禁用态的反馈。

完整的 HTML / CSS / JS 都附在上方卡片的「源码」标签页里,复制即可复用。