/** * 卡片渲染组件 */ class CardRenderer { /** * 渲染帖子卡片列表 * @param {Array} notes - 帖子数组 * @param {HTMLElement} container - 容器元素 */ static renderNotes(notes, container) { if (!notes || notes.length === 0) { container.innerHTML = `
📭

该特征暂无搜索结果

`; return; } container.innerHTML = notes.map(note => this.renderNoteCard(note)).join(''); // 初始化轮播图 this.initCarousels(container); } /** * 渲染单个帖子卡片 * @param {Object} noteData - 帖子数据 * @returns {string} HTML字符串 */ static renderNoteCard(noteData) { const note = noteData.note_card || noteData; // 提取数据 const title = note.display_title || '无标题'; const desc = note.desc || ''; const user = note.user || {}; const interactInfo = note.interact_info || {}; const images = note.image_list || []; const timestamp = note.publish_timestamp; // 格式化时间 const timeStr = this.formatTime(timestamp); // 格式化数字 const likeCount = this.formatNumber(interactInfo.liked_count); const commentCount = this.formatNumber(interactInfo.comment_count); const collectCount = this.formatNumber(interactInfo.collected_count); const shareCount = this.formatNumber(interactInfo.shared_count); return `
${user.nickname}
${images.length > 0 ? ` ` : ''}

${this.escapeHtml(title)}

${this.escapeHtml(desc)}
${desc.length > 150 ? ` 展开全文 ` : ''}
❤️ ${likeCount}
💬 ${commentCount}
${collectCount}
🔗 ${shareCount}
`; } /** * 初始化所有轮播图 * @param {HTMLElement} container - 容器元素 */ static initCarousels(container) { const carouselContainers = container.querySelectorAll('[data-carousel-container]'); carouselContainers.forEach((carouselContainer, index) => { const card = carouselContainer.closest('.note-card'); // 从容器中找到对应的图片数据 // 这里需要从原始数据中获取,所以我们先存储在 data 属性中 const carouselIndex = Array.from(container.querySelectorAll('[data-carousel-container]')).indexOf(carouselContainer); // 临时方案:从全局变量获取(在 renderNotes 时设置) if (window.__currentNotes && window.__currentNotes[carouselIndex]) { const note = window.__currentNotes[carouselIndex].note_card || window.__currentNotes[carouselIndex]; const images = note.image_list || []; if (images.length > 0) { new Carousel(carouselContainer, images); } } }); // 绑定展开/折叠事件 this.bindDescToggle(container); } /** * 绑定描述文本展开/折叠 * @param {HTMLElement} container - 容器元素 */ static bindDescToggle(container) { const toggles = container.querySelectorAll('[data-desc-toggle]'); toggles.forEach(toggle => { toggle.addEventListener('click', () => { const desc = toggle.previousElementSibling; const isExpanded = desc.classList.contains('expanded'); if (isExpanded) { desc.classList.remove('expanded'); toggle.textContent = '展开全文'; } else { desc.classList.add('expanded'); toggle.textContent = '收起'; } }); }); } /** * 格式化时间戳 * @param {number} timestamp - Unix时间戳(秒) * @returns {string} 格式化的时间字符串 */ static formatTime(timestamp) { if (!timestamp) return '未知时间'; const date = new Date(timestamp * 1000); const now = new Date(); const diff = now - date; // 小于1分钟 if (diff < 60 * 1000) { return '刚刚'; } // 小于1小时 if (diff < 60 * 60 * 1000) { const minutes = Math.floor(diff / (60 * 1000)); return `${minutes}分钟前`; } // 小于24小时 if (diff < 24 * 60 * 60 * 1000) { const hours = Math.floor(diff / (60 * 60 * 1000)); return `${hours}小时前`; } // 小于7天 if (diff < 7 * 24 * 60 * 60 * 1000) { const days = Math.floor(diff / (24 * 60 * 60 * 1000)); return `${days}天前`; } // 显示具体日期 const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); if (year === now.getFullYear()) { return `${month}-${day}`; } return `${year}-${month}-${day}`; } /** * 格式化数字 * @param {number|string} num - 数字 * @returns {string} 格式化的数字字符串 */ static formatNumber(num) { if (!num) return '0'; const n = parseInt(num); if (n >= 10000) { return (n / 10000).toFixed(1) + 'w'; } if (n >= 1000) { return (n / 1000).toFixed(1) + 'k'; } return n.toString(); } /** * HTML 转义 * @param {string} text - 原始文本 * @returns {string} 转义后的文本 */ static escapeHtml(text) { if (!text) return ''; const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } /** * 显示加载状态 * @param {HTMLElement} container - 容器元素 */ static showLoading(container) { container.innerHTML = '
加载中...
'; } /** * 显示错误状态 * @param {HTMLElement} container - 容器元素 * @param {string} message - 错误消息 */ static showError(container, message) { container.innerHTML = `

${message}

`; } }