/** * 好友开关组件 - 主要入口 * 负责显示悬浮按钮和控制好友列表弹窗 */ class FriendToggle { constructor(options = {}) { // 检查是否已经存在实例 if (FriendToggle.instance) { return FriendToggle.instance; } // 默认配置 this.config = { position: options.position || 'bottom-right', size: options.size || 'medium', theme: options.theme || 'default', zIndex: options.zIndex || 9999, ...options }; this.isVisible = true; this.element = null; this.friendListModal = null; this.init(); // 设置单例 FriendToggle.instance = this; } // 静态方法获取实例 static getInstance(options = {}) { if (!FriendToggle.instance) { new FriendToggle(options); } return FriendToggle.instance; } // 初始化组件 init() { this.createStyles(); this.createElement(); this.bindEvents(); this.updatePosition(); this.updateTheme(); this.updateSize(); // 初始化好友列表弹窗 this.friendListModal = new (window.FriendListModal || FriendListModal)(); } // 创建样式 createStyles() { if (document.getElementById('friend-toggle-styles')) return; const style = document.createElement('style'); style.id = 'friend-toggle-styles'; style.textContent = ` .friend-toggle { position: fixed; cursor: pointer; user-select: none; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); border-radius: 20px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); display: flex; align-items: center; justify-content: center; backdrop-filter: blur(10px); transform-origin: center; z-index: ${this.config.zIndex}; border: 2px solid rgba(255, 255, 255, 0.2); } .friend-toggle:hover { transform: scale(1.05); box-shadow: 0 6px 25px rgba(0, 0, 0, 0.2); } .friend-toggle:active { transform: scale(0.95); } .friend-toggle.hidden { opacity: 0; transform: scale(0.8); pointer-events: none; } .friend-toggle .icon { font-size: 12px; font-weight: 600; transition: all 0.3s ease; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.1)); display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; letter-spacing: 0.5px; } /* 尺寸样式 */ .friend-toggle.small { width: 50px; height: 35px; border-radius: 18px; } .friend-toggle.small .icon { font-size: 10px; } .friend-toggle.medium { width: 60px; height: 40px; border-radius: 20px; } .friend-toggle.medium .icon { font-size: 12px; } .friend-toggle.large { width: 70px; height: 45px; border-radius: 23px; } .friend-toggle.large .icon { font-size: 14px; } /* 主题样式 */ .friend-toggle.default { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; } .friend-toggle.dark { background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%); color: white; } .friend-toggle.colorful { background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 50%, #fecfef 100%); color: #333; } /* 位置样式 */ .friend-toggle.top-left { top: 20px; left: 20px; } .friend-toggle.top-right { top: 20px; right: 20px; } .friend-toggle.bottom-left { bottom: 20px; left: 20px; } .friend-toggle.bottom-right { bottom: 20px; right: 20px; } /* 动画效果 */ @keyframes bounce { 0%, 20%, 50%, 80%, 100% { transform: translateY(0); } 40% { transform: translateY(-10px); } 60% { transform: translateY(-5px); } } .friend-toggle.bounce { animation: bounce 0.6s; } `; document.head.appendChild(style); } // 创建DOM元素 createElement() { this.element = document.createElement('div'); this.element.className = `friend-toggle ${this.config.position} ${this.config.size} ${this.config.theme}`; // 创建图标 const icon = document.createElement('div'); icon.className = 'icon'; icon.textContent = '好友'; this.element.appendChild(icon); document.body.appendChild(this.element); } // 绑定事件 bindEvents() { // 添加拖动功能 this.makeDraggable(); this.element.addEventListener('click', (e) => { e.stopPropagation(); // 如果正在拖动,不触发点击事件 if (this.isDragging) { return; } this.toggleFriendList(); }); } // 添加拖动功能 makeDraggable() { let isDragging = false; let startX, startY, initialX, initialY; this.element.addEventListener('mousedown', (e) => { isDragging = true; this.isDragging = false; // 初始设置为false,真正拖动时才设为true startX = e.clientX; startY = e.clientY; const rect = this.element.getBoundingClientRect(); initialX = rect.left; initialY = rect.top; this.element.style.cursor = 'grabbing'; this.element.style.transition = 'none'; e.preventDefault(); }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; const deltaX = e.clientX - startX; const deltaY = e.clientY - startY; // 如果移动距离超过5px,认为是拖动而不是点击 if (Math.abs(deltaX) > 5 || Math.abs(deltaY) > 5) { this.isDragging = true; } const newX = initialX + deltaX; const newY = initialY + deltaY; // 限制拖动范围在屏幕内 const maxX = window.innerWidth - this.element.offsetWidth; const maxY = window.innerHeight - this.element.offsetHeight; const constrainedX = Math.max(0, Math.min(newX, maxX)); const constrainedY = Math.max(0, Math.min(newY, maxY)); this.element.style.left = constrainedX + 'px'; this.element.style.top = constrainedY + 'px'; this.element.style.right = 'auto'; this.element.style.bottom = 'auto'; }); document.addEventListener('mouseup', () => { if (isDragging) { isDragging = false; this.element.style.cursor = 'pointer'; this.element.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)'; // 延迟重置isDragging标志,防止拖动后立即触发点击 setTimeout(() => { this.isDragging = false; }, 100); } }); } // 切换好友列表显示 toggleFriendList() { this.addBounceEffect(); if (this.friendListModal) { this.friendListModal.toggle(); } // 触发自定义事件 const event = new CustomEvent('friendToggleClick', { detail: { instance: this } }); document.dispatchEvent(event); } // 添加弹跳效果 addBounceEffect() { this.element.classList.remove('bounce'); this.element.offsetHeight; // 强制重排 this.element.classList.add('bounce'); setTimeout(() => { this.element.classList.remove('bounce'); }, 600); } // 显示组件 show() { this.isVisible = true; this.element.classList.remove('hidden'); } // 隐藏组件 hide() { this.isVisible = false; this.element.classList.add('hidden'); } // 更新位置 updatePosition() { this.element.className = this.element.className.replace( /(top|bottom)-(left|right)/g, this.config.position ); } // 更新主题 updateTheme() { this.element.className = this.element.className.replace( /(default|dark|colorful)/g, this.config.theme ); } // 更新大小 updateSize() { this.element.className = this.element.className.replace( /(small|medium|large)/g, this.config.size ); } // 更新配置 updateConfig(newConfig) { Object.assign(this.config, newConfig); this.updatePosition(); this.updateTheme(); this.updateSize(); } // 销毁组件 destroy() { if (this.friendListModal) { this.friendListModal.destroy(); this.friendListModal = null; } if (this.element && this.element.parentNode) { this.element.parentNode.removeChild(this.element); } // 移除样式 const styles = document.getElementById('friend-toggle-styles'); if (styles) { styles.parentNode.removeChild(styles); } this.element = null; FriendToggle.instance = null; } } // 暴露给全局使用 if (typeof window !== 'undefined') { window.FriendToggle = FriendToggle; } // 支持模块导入 if (typeof module !== 'undefined' && module.exports) { module.exports = FriendToggle; } // 支持 ES6 导入 export default FriendToggle;