/**
* 卡片渲染组件
*/
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 `
${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 = `
`;
}
}