什么是 Ant Design 彩蛋按钮

Ant Design(简称 AntD)是由蚂蚁集团开发的一套企业级 UI 设计语言和 React UI 框架。在 Ant Design 的组件库中,”彩蛋按钮”(Easter Egg Button)并不是一个官方的正式组件名称,而是开发者社区对某些具有特殊交互效果或隐藏功能的按钮的俗称。这些按钮通常在特定条件下触发,提供超出常规功能的惊喜体验。

彩蛋按钮的核心特征包括:

  • 隐藏性:不会在常规文档中明确说明,需要用户主动探索发现
  • 条件触发:需要特定的交互序列、频率或组合操作
  1. 惊喜感:提供超出预期的视觉反馈或功能反馈
  • 趣味性:增加产品的趣味性和用户粘性

Ant Design 中常见的彩蛋按钮类型

1. 连续点击型彩蛋

这是最常见的彩蛋类型,通过快速连续点击按钮触发特殊效果。

示例场景:在 Ant Design 的官方文档网站中,某些按钮在连续快速点击 5-10 次后会触发特殊动画。

// 实现连续点击彩蛋的代码示例
import React, { useState, useRef } from 'react';
import { Button, message } from 'antd';
import { HeartOutlined } from '@ant-design/icons';

const EasterEggButton = () => {
  const [clickCount, setClickCount] = useState(0);
  const [isCelebrating, setIsCelebrating] = useState(false);
  const timerRef = useRef(null);

  const handleClick = () => {
    // 清除之前的定时器
    if (timerRef.current) {
      clearTimeout(timerRef.current);
    }

    // 增加点击计数
    const newCount = clickCount + 1;
    setClickCount(newCount);

    // 设置新的定时器,300ms 后重置计数
    timerRef.current = setTimeout(() => {
      setClickCount(0);
    }, 300);

    // 检查是否达到触发条件(例如连续点击 5 次)
    if (newCount >= 5) {
      triggerEasterEgg();
      setClickCount(0); // 重置计数
    }
  };

  const triggerEasterEgg = () => {
    setIsCelebrating(true);
    message.success('🎉 恭喜!你发现了隐藏彩蛋!');
    
    // 触发庆祝动画
    setTimeout(() => {
      setIsCelebrating(false);
    }, 3000);
  };

  return (
    <div style={{ textAlign: 'center', padding: '20px' }}>
      <Button
        type="primary"
        icon={<HeartOutlined />}
        onClick={handleClick}
        size="large"
        style={{
          transform: isCelebrating ? 'scale(1.2)' : 'scale(1)',
          transition: 'all 0.3s ease',
          backgroundColor: isCelebrating ? '#ff4d4f' : '#1890ff'
        }}
      >
        {isCelebrating ? '❤️ 爱你!' : '点击我试试'}
      </Button>
      <p style={{ marginTop: '10px', color: '#666' }}>
        连续快速点击 5 次试试看!
      </p>
    </div>
  );
};

export default EasterEggButton;

2. 长按型彩蛋

通过长按按钮一定时间触发特殊效果。

// 长按彩蛋实现
import React, { useState, useEffect, useRef } from 'react';
import { Button } from 'antd';

const LongPressEasterEgg = () => {
  const [pressStartTime, setPressStartTime] = useState(null);
  const [isLongPress, setIsLongPress] = useState(false);
  const longPressTimer = useRef(null);

  const handleMouseDown = () => {
    setPressStartTime(Date.now());
    longPressTimer.current = setTimeout(() => {
      setIsLongPress(true);
      triggerLongPressEffect();
    }, 1000); // 1秒长按
  };

  const handleMouseUp = () => {
    clearTimeout(longPressTimer.current);
    setPressStartTime(null);
    setIsLongPress(false);
  };

  const triggerLongPressEffect = () => {
    // 创建爆炸粒子效果
    createParticles();
    // 播放音效(如果浏览器支持)
    if ('speechSynthesis' in window) {
      const utterance = new SpeechSynthesisUtterance('彩蛋触发!');
      speechSynthesis.speak(utterance);
    }
  };

  const createParticles = () => {
    const button = document.querySelector('#long-press-btn');
    if (!button) return;

    const rect = button.getBoundingClientRect();
    const centerX = rect.left + rect.width / 2;
    const centerY = rect.top + rect.height / 2;

    for (let i = 0; i < 20; i++) {
      const particle = document.createElement('div');
      particle.style.cssText = `
        position: fixed;
        width: 8px;
        height: 8px;
        background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
        border-radius: 50%;
        left: ${centerX}px;
        top: ${centerY}px;
        pointer-events: none;
        z-index: 9999;
        animation: particle-burst 1s ease-out forwards;
      `;
      
      // 随机方向
      const angle = (Math.PI * 2 * i) / 20;
      const velocity = 100 + Math.random() * 100;
      const tx = Math.cos(angle) * velocity;
      const ty = Math.sin(angle) * velocity;
      
      particle.style.setProperty('--tx', `${tx}px`);
      particle.style.setProperty('--ty', `${ty}px`);
      
      document.body.appendChild(particle);
      
      setTimeout(() => particle.remove(), 1000);
    }
  };

  // 添加粒子动画样式
  useEffect(() => {
    const style = document.createElement('style');
    style.textContent = `
      @keyframes particle-burst {
        0% {
          transform: translate(0, 0) scale(1);
          opacity: 1;
        }
        100% {
          transform: translate(var(--tx), var(--ty)) scale(0);
          opacity: 0;
        }
      }
    `;
    document.head.appendChild(style);
    return () => style.remove();
  }, []);

  return (
    <div style={{ textAlign: 'center', padding: '20px' }}>
      <Button
        id="long-press-btn"
        type="dashed"
        size="large"
        onMouseDown={handleMouseDown}
        onMouseUp={handleMouseUp}
        onMouseLeave={handleMouseUp}
        onTouchStart={handleMouseDown}
        onTouchEnd={handleMouseUp}
        style={{
          minWidth: '150px',
          transition: 'all 0.3s ease',
          backgroundColor: isLongPress ? '#52c41a' : undefined
        }}
      >
        {isLongPress ? '🎉 彩蛋触发!' : '长按我 1 秒'}
      </Button>
      <p style={{ marginTop: '10px', color: '#666' }}>
        长按按钮直到它变绿
      </p>
    </div>
  );
};

export default LongPressEasterEgg;

3. 组合键型彩蛋

通过特定的键盘组合触发,适合桌面端应用。

// 组合键彩蛋实现
import React, { useEffect, useState } from 'react';
import { Button, Tag } from 'antd';

const KonamiCodeEasterEgg = () => {
  const [inputSequence, setInputSequence] = useState([]);
  const [isUnlocked, setIsUnlocked] = useState(false);
  
  // Konami Code: ↑ ↑ ↓ ↓ ← → ← → B A
  const KONAMI_CODE = ['ArrowUp', 'ArrowUp', 'ArrowDown', 'ArrowDown', 
                       'ArrowLeft', 'ArrowRight', 'ArrowLeft', 'ArrowRight', 
                       'b', 'a'];
  
  useEffect(() => {
    const handleKeyDown = (e) => {
      // 记录最近的 10 次按键
      const newSequence = [...inputSequence, e.key].slice(-10);
      setInputSequence(newSequence);
      
      // 检查是否匹配 Konami Code
      const isMatch = newSequence.slice(-KONAMI_CODE.length)
        .every((key, index) => key.toLowerCase() === KONAMI_CODE[index].toLowerCase());
      
      if (isMatch && !isUnlocked) {
        setIsUnlocked(true);
        triggerKonamiEasterEgg();
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [inputSequence, isUnlocked]);

  const triggerKonamiEasterEgg = () => {
    // 1. 显示提示消息
    const notification = document.createElement('div');
    notification.style.cssText = `
      position: fixed;
      top: 20px;
      left: 50%;
      transform: translateX(-50%);
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      color: white;
      padding: 15px 30px;
      border-radius: 8px;
      font-size: 18px;
      font-weight: bold;
      z-index: 9999;
      animation: slideDown 0.5s ease-out;
    `;
    notification.textContent = '🎮 Konami Code 已激活!解锁隐藏模式!';
    document.body.appendChild(notification);

    // 2. 改变页面主题
    document.body.style.filter = 'hue-rotate(180deg)';
    document.body.style.transition = 'filter 1s ease';

    // 3. 创建全屏粒子效果
    createFullscreenConfetti();

    // 4. 3秒后恢复
    setTimeout(() => {
      notification.remove();
      document.body.style.filter = '';
      setIsUnlocked(false);
    }, 5000);
  };

  const createFullscreenConfetti = () => {
    const colors = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#96ceb4', '#ffeaa7'];
    for (let i = 0; i < 100; i++) {
      setTimeout(() => {
        const confetti = document.createElement('div');
        confetti.style.cssText = `
          position: fixed;
          width: 10px;
          height: 10px;
          background: ${colors[Math.floor(Math.random() * colors.length)]};
          left: ${Math.random() * 100}vw;
          top: -10px;
          pointer-events: none;
          z-index: 9998;
          animation: confetti-fall ${2 + Math.random() * 2}s linear forwards;
        `;
        document.body.appendChild(confetti);
        setTimeout(() => confetti.remove(), 4000);
      }, i * 30);
    }
  };

  // 添加动画样式
  useEffect(() => {
    const style = document.createElement('style');
    style.textContent = `
      @keyframes slideDown {
        from { transform: translateX(-50%) translateY(-100%); opacity: 0; }
        to { transform: translateX(-50%) translateY(0); opacity: 1; }
      }
      @keyframes confetti-fall {
        to {
          transform: translateY(100vh) rotate(360deg);
          opacity: 0;
        }
      }
    `;
    document.head.appendChild(style);
    return () => style.remove();
  }, []);

  return (
    <div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
      <h2>🎮 Konami Code 彩蛋</h2>
      <p>在页面任意位置输入以下序列:</p>
      <div style={{ background: '#f5f5f5', padding: '10px', borderRadius: '4px', margin: '10px 0' }}>
        <Tag color="blue">↑</Tag>
        <Tag color="blue">↑</Tag>
        <Tag color="blue">↓</Tag>
        <Tag color="blue">↓</Tag>
        <Tag color="blue">←</Tag>
        <Tag color="blue">→</Tag>
        <Tag color="blue">←</Tag>
        <Tag color="blue">→</Tag>
        <Tag color="red">B</Tag>
        <Tag color="red">A</Tag>
      </div>
      <p style={{ color: '#666' }}>
        当前按键记录:{inputSequence.length > 0 ? inputSequence.join(' → ') : '等待输入...'}
      </p>
      {isUnlocked && (
        <div style={{ marginTop: '20px', padding: '15px', background: '#f6ffed', border: '1px solid #b7eb8f', borderRadius: '4px' }}>
          <strong>🎉 彩蛋已解锁!</strong>
          <p>页面主题已改变,享受惊喜效果!</p>
        </div>
      )}
    </div>
  );
};

export default KonamiCodeEasterEgg;

4. 拖拽交互型彩蛋

通过拖拽按钮到特定区域触发。

// 拖拽彩蛋实现
import React, { useState, useRef } from 'react';
import { Button, Card } from 'antd';

const DragEasterEgg = () => {
  const [position, setPosition] = useState({ x: 0, y: 0 });
  const [isDragging, setIsDragging] = useState(false);
  const [isDropped, setIsDropped] = useState(false);
  const dragRef = useRef(null);
  const dropZoneRef = useRef(null);

  const handleDragStart = (e) => {
    setIsDragging(true);
    e.dataTransfer.effectAllowed = 'move';
    e.dataTransfer.setData('text/html', e.target.innerHTML);
  };

  const handleDragEnd = (e) => {
    setIsDragging(false);
  };

  const handleDragOver = (e) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = 'move';
  };

  const handleDrop = (e) => {
    e.preventDefault();
    const dropZone = dropZoneRef.current;
    const dragElement = dragRef.current;
    
    if (dropZone && dragElement) {
      const dropZoneRect = dropZone.getBoundingClientRect();
      const dragRect = dragElement.getBoundingClientRect();
      
      // 检查是否在投放区域内
      if (
        dragRect.left >= dropZoneRect.left &&
        dragRect.right <= dropZoneRect.right &&
        dragRect.top >= dropZoneRect.top &&
        dragRect.bottom <= dropZoneRect.bottom
      ) {
        setIsDropped(true);
        triggerDragEasterEgg();
      }
    }
  };

  const triggerDragEasterEgg = () => {
    // 创建彩虹效果
    const colors = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#96ceb4', '#ffeaa7', '#a8e6cf'];
    const dropZone = dropZoneRef.current;
    if (!dropZone) return;

    // 添加彩虹边框动画
    dropZone.style.animation = 'rainbow-border 2s linear infinite';
    
    // 在投放区域创建彩色粒子
    for (let i = 0; i < 30; i++) {
      const particle = document.createElement('div');
      particle.style.cssText = `
        position: absolute;
        width: 6px;
        height: 6px;
        background: ${colors[Math.floor(Math.random() * colors.length)]};
        border-radius: 50%;
        left: ${50 + (Math.random() - 0.5) * 80}%;
        top: ${50 + (Math.random() - 0.5) * 80}%;
        pointer-events: none;
        animation: particle-float ${1 + Math.random() * 2}s ease-out forwards;
      `;
      dropZone.appendChild(particle);
      setTimeout(() => particle.remove(), 3000);
    }

    // 显示成功消息
    const successMsg = document.createElement('div');
    successMsg.textContent = '✨ 拖拽彩蛋成功!';
    successMsg.style.cssText = `
      position: absolute;
      top: -30px;
      left: 50%;
      transform: translateX(-50%);
      background: #52c41a;
      color: white;
      padding: 5px 10px;
      border-radius: 4px;
      font-size: 12px;
      animation: fadeInOut 2s ease-out;
    `;
    dropZone.appendChild(successMsg);
    setTimeout(() => successMsg.remove(), 2000);
  };

  // 添加动画样式
  const addAnimationStyles = () => {
    const style = document.createElement('style');
    style.textContent = `
      @keyframes rainbow-border {
        0% { border-color: #ff6b6b; box-shadow: 0 0 10px #ff6b6b; }
        25% { border-color: #4ecdc4; box-shadow: 0 0 10px #4ecdc4; }
        50% { border-color: #45b7d1; box-shadow: 0 0 10px #45b7d1; }
        75% { border-color: #96ceb4; box-shadow: 0 0 10px #96ceb4; }
        100% { border-color: #ff6b6b; box-shadow: 0 0 10px #ff6b6b; }
      }
      @keyframes particle-float {
        0% { transform: translate(0, 0) scale(1); opacity: 1; }
        100% { transform: translate(${(Math.random() - 0.5) * 200}px, ${(Math.random() - 0.5) * 200}px) scale(0); opacity: 0; }
      }
      @keyframes fadeInOut {
        0% { opacity: 0; transform: translateX(-50%) translateY(10px); }
        20% { opacity: 1; transform: translateX(-50%) translateY(0); }
        80% { opacity: 1; transform: translateX(-50%) translateY(0); }
        100% { opacity: 0; transform: translateX(-50%) translateY(-10px); }
      }
    `;
    document.head.appendChild(style);
  };

  React.useEffect(() => {
    addAnimationStyles();
  }, []);

  return (
    <div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
      <h3>🎯 拖拽彩蛋挑战</h3>
      <p>将下面的按钮拖拽到虚线框内:</p>
      
      <div style={{ display: 'flex', gap: '20px', marginTop: '20px' }}>
        {/* 可拖拽按钮 */}
        <div
          ref={dragRef}
          draggable
          onDragStart={handleDragStart}
          onDragEnd={handleDragEnd}
          style={{
            cursor: 'move',
            padding: '10px',
            background: isDragging ? '#1890ff' : '#f0f0f0',
            color: isDragging ? 'white' : 'black',
            border: '2px solid #1890ff',
            borderRadius: '4px',
            userSelect: 'none',
            transition: 'all 0.2s ease'
          }}
        >
          🚀 拖拽我
        </div>

        {/* 投放区域 */}
        <div
          ref={dropZoneRef}
          onDragOver={handleDragOver}
          onDrop={handleDrop}
          style={{
            width: '150px',
            height: '80px',
            border: isDropped ? '3px dashed #52c41a' : '3px dashed #d9d9d9',
            borderRadius: '8px',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            background: isDropped ? '#f6ffed' : 'white',
            position: 'relative',
            transition: 'all 0.3s ease'
          }}
        >
          {isDropped ? '🎉 成功!' : '投放区域'}
        </div>
      </div>

      {isDropped && (
        <div style={{ marginTop: '20px', padding: '15px', background: '#e6f7ff', border: '1px solid #91d5ff', borderRadius: '4px' }}>
          <strong>🎊 拖拽彩蛋触发!</strong>
          <p>你成功发现了隐藏的拖拽交互彩蛋!</p>
        </div>
      )}
    </div>
  );
};

export default DragEasterEgg;

如何在 Ant Design 项目中实现彩蛋按钮

1. 基础实现步骤

要在你的 Ant Design 项目中添加彩蛋按钮,请遵循以下步骤:

步骤 1:创建彩蛋组件

// components/EasterEggButton.jsx
import React, { useState, useRef } from 'react';
import { Button, message } from 'antd';
import { StarOutlined } from '@ant-design/icons';

const EasterEggButton = ({ triggerCount = 5, children = '点击我' }) => {
  const [count, setCount] = useState(0);
  const timerRef = useRef(null);

  const handleClick = () => {
    if (timerRef.current) clearTimeout(timerRef.current);
    
    const newCount = count + 1;
    setCount(newCount);

    timerRef.current = setTimeout(() => {
      setCount(0);
    }, 1000);

    if (newCount >= triggerCount) {
      // 触发彩蛋
      message.success('✨ 你发现了隐藏功能!');
      setCount(0);
      
      // 这里可以调用更复杂的彩蛋函数
      triggerSpecialEffect();
    }
  };

  const triggerSpecialEffect = () => {
    // 实现你的彩蛋逻辑
    console.log('彩蛋触发!');
  };

  return (
    <Button
      type="primary"
      icon={<StarOutlined />}
      onClick={handleClick}
    >
      {children}
    </Button>
  );
};

export default EasterEggButton;

步骤 2:在页面中使用

// pages/MyPage.jsx
import React from 'react';
import { Layout } from 'antd';
import EasterEggButton from '../components/EasterEggButton';

const MyPage = () => {
  return (
    <Layout style={{ padding: '20px' }}>
      <h1>探索页面</h1>
      <EasterEggButton triggerCount={5}>
        点击 5 次触发彩蛋
      </EasterEggButton>
    </Layout>
  );
};

export default MyPage;

2. 高级彩蛋实现模式

模式 1:状态管理集成

// 使用 Context 管理全局彩蛋状态
import React, { createContext, useContext, useState } from 'react';

const EasterEggContext = createContext();

export const EasterEggProvider = ({ children }) => {
  const [unlockedEggs, setUnlockedEggs] = useState(new Set());

  const unlockEgg = (eggId) => {
    setUnlockedEggs(prev => new Set([...prev, eggId]));
    // 可以在这里保存到 localStorage
    localStorage.setItem('unlockedEggs', JSON.stringify([...unlockedEggs, eggId]));
  };

  const isEggUnlocked = (eggId) => unlockedEggs.has(eggId);

  return (
    <EasterEggContext.Provider value={{ unlockEgg, isEggUnlocked }}>
      {children}
    </EasterEggContext.Provider>
  );
};

export const useEasterEgg = () => useContext(EasterEggContext);

模式 2:彩蛋管理器

// utils/EasterEggManager.js
class EasterEggManager {
  constructor() {
    this.eggs = new Map();
    this.unlocked = new Set();
    this.loadUnlockedFromStorage();
  }

  // 注册彩蛋
  registerEgg(id, config) {
    this.eggs.set(id, {
      id,
      trigger: config.trigger, // 触发条件函数
      action: config.action,   // 触发后的动作
      hint: config.hint || '', // 提示信息
      ...config
    });
  }

  // 检查触发条件
  checkTrigger(eventData) {
    this.eggs.forEach((egg, id) => {
      if (!this.unlocked.has(id) && egg.trigger(eventData)) {
        this.triggerEgg(id);
      }
    });
  }

  // 触发彩蛋
  triggerEgg(id) {
    const egg = this.eggs.get(id);
    if (egg) {
      this.unlocked.add(id);
      this.saveUnlockedToStorage();
      egg.action();
      this.showNotification(egg);
    }
  }

  // 显示通知
  showNotification(egg) {
    // 创建自定义通知
    const notification = document.createElement('div');
    notification.style.cssText = `
      position: fixed;
      top: 20px;
      right: 20px;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      color: white;
      padding: 15px 20px;
      border-radius: 8px;
      box-shadow: 0 4px 12px rgba(0,0,0,0.15);
      z-index: 9999;
      animation: slideIn 0.5s ease-out;
      max-width: 300px;
    `;
    notification.innerHTML = `
      <div style="font-weight: bold; margin-bottom: 5px;">🎉 彩蛋解锁!</div>
      <div style="font-size: 14px;">${egg.hint}</div>
    `;
    document.body.appendChild(notification);
    setTimeout(() => {
      notification.style.animation = 'slideOut 0.5s ease-in forwards';
      setTimeout(() => notification.remove(), 500);
    }, 3000);
  }

  // 本地存储
  loadUnlockedFromStorage() {
    try {
      const saved = localStorage.getItem('unlockedEggs');
      if (saved) {
        this.unlocked = new Set(JSON.parse(saved));
      }
    } catch (e) {
      console.warn('无法加载彩蛋状态', e);
    }
  }

  saveUnlockedToStorage() {
    try {
      localStorage.setItem('unlockedEggs', JSON.stringify([...this.unlocked]));
    } catch (e) {
      console.warn('无法保存彩蛋状态', e);
    }
  }

  // 获取所有彩蛋状态
  getStatus() {
    return {
      total: this.eggs.size,
      unlocked: this.unlocked.size,
      percentage: (this.unlocked.size / this.eggs.size) * 100
    };
  }
}

// 全局实例
export const easterEggManager = new EasterEggManager();

3. 实际应用示例

示例 1:在 Ant Design 表单中添加彩蛋

import React, { useState } from 'react';
import { Form, Input, Button, Card, message } from 'antd';
import { UserOutlined, LockOutlined } from '@ant-design/icons';
import { easterEggManager } from '../utils/EasterEggManager';

const LoginFormWithEasterEgg = () => {
  const [clickCount, setClickCount] = useState(0);

  // 注册彩蛋:在用户名输入框快速点击 10 次
  React.useEffect(() => {
    easterEggManager.registerEgg('username-click', {
      trigger: (data) => data.type === 'username-click' && data.count >= 10,
      action: () => {
        message.success('🎉 开发者模式已激活!');
        // 这里可以添加开发者工具等高级功能
      },
      hint: '在用户名框快速点击 10 次解锁开发者模式'
    });
  }, []);

  const handleUsernameClick = () => {
    const newCount = clickCount + 1;
    setClickCount(newCount);
    
    easterEggManager.checkTrigger({
      type: 'username-click',
      count: newCount
    });

    // 重置计数
    setTimeout(() => setClickCount(0), 1000);
  };

  return (
    <Card title="登录" style={{ maxWidth: 400, margin: '50px auto' }}>
      <Form>
        <Form.Item
          name="username"
          rules={[{ required: true, message: '请输入用户名' }]}
        >
          <Input
            prefix={<UserOutlined />}
            placeholder="用户名"
            onClick={handleUsernameClick}
          />
        </Form.Item>
        <Form.Item
          name="password"
          rules={[{ required: true, message: '请输入密码' }]}
        >
          <Input.Password
            prefix={<LockOutlined />}
            placeholder="密码"
          />
        </Form.Item>
        <Form.Item>
          <Button type="primary" htmlType="submit" block>
            登录
          </Button>
        </Form.Item>
      </Form>
    </Card>
  );
};

export default LoginFormWithEasterEgg;

示例 2:页面加载彩蛋

// 在页面加载时触发的彩蛋
import React, { useEffect, useState } from 'react';
import { Spin, Result, Button } from 'antd';

const LoadingScreenWithEasterEgg = () => {
  const [loading, setLoading] = useState(true);
  const [eggTriggered, setEggTriggered] = useState(false);

  useEffect(() => {
    // 检查是否在特定时间(如 4 月 1 日)访问
    const today = new Date();
    const isAprilFools = today.getMonth() === 3 && today.getDate() === 1;

    // 检查是否在特定时段(如凌晨 3:33)
    const now = new Date();
    const isSpecialTime = now.getHours() === 3 && now.getMinutes() === 33;

    if (isAprilFools || isSpecialTime) {
      // 延迟 2 秒显示彩蛋
      const timer = setTimeout(() => {
        setEggTriggered(true);
        setLoading(false);
        triggerLoadingEasterEgg();
      }, 2000);

      return () => clearTimeout(timer);
    } else {
      // 正常加载
      const timer = setTimeout(() => setLoading(false), 1500);
      return () => clearTimeout(timer);
    }
  }, []);

  const triggerLoadingEasterEgg = () => {
    // 创建全屏彩色背景
    document.body.style.background = 'linear-gradient(45deg, #ff6b6b, #4ecdc4, #45b7d1, #96ceb4)';
    document.body.style.backgroundSize = '400% 400%';
    document.body.style.animation = 'gradient-shift 5s ease infinite';
    
    // 添加动画样式
    const style = document.createElement('style');
    style.textContent = `
      @keyframes gradient-shift {
        0% { background-position: 0% 50%; }
        50% { background-position: 100% 50%; }
        100% { background-position: 0% 50%; }
      }
    `;
    document.head.appendChild(style);
  };

  if (loading) {
    return (
      <div style={{ 
        display: 'flex', 
        justifyContent: 'center', 
        alignItems: 'center', 
        height: '100vh',
        flexDirection: 'column',
        gap: '20px'
      }}>
        <Spin size="large" tip="加载中..." />
        {eggTriggered && <p style={{ color: '#1890ff' }}>✨ 发现特殊时刻!</p>}
      </div>
    );
  }

  if (eggTriggered) {
    return (
      <Result
        status="success"
        title="🎉 惊喜时刻!"
        subTitle="你访问了一个特殊的时间点,解锁了隐藏的加载彩蛋!"
        extra={[
          <Button type="primary" key="home" href="/">
            返回首页
          </Button>,
          <Button key="reset" onClick={() => window.location.reload()}>
            再来一次
          </Button>,
        ]}
      />
    );
  }

  return <div>正常内容</div>;
};

export default LoadingScreenWithEasterEgg;

最佳实践和注意事项

1. 设计原则

  • 适度原则:彩蛋不应影响主要功能,避免过度设计
  • 可发现性:彩蛋应该有一定的线索或暗示,而不是完全随机
  • 价值性:彩蛋应该提供真正的惊喜或实用价值
  • 包容性:确保彩蛋不会让不触发的用户感到被排斥

2. 性能考虑

// 优化彩蛋性能的建议
const PerformanceOptimizedEasterEgg = () => {
  // 使用防抖和节流
  const debounce = (fn, delay) => {
    let timer = null;
    return (...args) => {
      clearTimeout(timer);
      timer = setTimeout(() => fn(...args), delay);
    };
  };

  // 使用 Intersection Observer 懒加载彩蛋
  useEffect(() => {
    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          // 只在元素可见时初始化彩蛋
          initializeEasterEgg();
        }
      });
    });

    const target = document.querySelector('#easter-egg-trigger');
    if (target) observer.observe(target);

    return () => observer.disconnect();
  }, []);

  // 避免内存泄漏
  useEffect(() => {
    const handleEvent = debounce((e) => {
      // 处理事件
    }, 100);

    window.addEventListener('scroll', handleEvent);
    return () => window.removeEventListener('scroll', handleEvent);
  }, []);

  return <div id="easter-egg-trigger">触发区域</div>;
};

3. 安全考虑

  • 避免敏感操作:彩蛋不应执行危险操作(如删除数据)
  • 用户隐私:不要在彩蛋中收集用户敏感信息
  • 可禁用:提供关闭彩蛋的选项,尊重用户偏好

4. 测试策略

// 彩蛋测试示例
import { render, fireEvent, screen } from '@testing-library/react';

describe('EasterEggButton', () => {
  it('should trigger easter egg after 5 clicks', () => {
    render(<EasterEggButton triggerCount={5} />);
    const button = screen.getByText(/点击我/i);
    
    // 快速点击 5 次
    for (let i = 0; i < 5; i++) {
      fireEvent.click(button);
    }
    
    // 验证彩蛋触发
    expect(screen.getByText(/彩蛋!/i)).toBeInTheDocument();
  });

  it('should reset count after timeout', async () => {
    jest.useFakeTimers();
    render(<EasterEggButton triggerCount={5} />);
    const button = screen.getByText(/点击我/i);
    
    fireEvent.click(button);
    fireEvent.click(button);
    
    // 快进时间
    jest.advanceTimersByTime(1000);
    
    // 点击次数应该已重置
    fireEvent.click(button);
    // 不应该触发彩蛋
    expect(screen.queryByText(/彩蛋!/i)).not.toBeInTheDocument();
  });
});

总结

Ant Design 彩蛋按钮是一种增强用户体验的趣味性功能,通过隐藏的交互模式为产品增添惊喜感。实现时需要注意:

  1. 选择合适的触发方式:根据用户行为习惯选择点击、长按、拖拽或组合键
  2. 平衡隐藏与发现:既要保持神秘感,又要提供足够的线索
  3. 确保不影响性能:使用防抖、节流和懒加载等优化技术
  4. 提供价值:彩蛋应该带来真正的惊喜或实用功能
  5. 考虑可访问性:确保彩蛋不会影响主要功能的使用

通过合理设计和实现,彩蛋按钮可以成为产品中的亮点,提升用户粘性和品牌好感度。记住,好的彩蛋应该让用户感到”我发现了宝藏”,而不是”这到底是什么鬼”。