Hiển thị bình luận mới nhất thông qua API Waline
1072 từ
5 phút
Hiển thị bình luận mới nhất thông qua API Waline
Nguồn API
Khi xem tài liệu API chính thức của Waline, tôi phát hiện ra rằng /api/comment?type=recentAPI có thể trả về dữ liệu bình luận mới nhất từ trang web. Vì vậy, tôi đã “thuần hóa” AI để viết một thành phần hiển thị bình luận phù hợp với chủ đề hiện tại, và cho đến nay, nó vẫn chưa gặp phải bất kỳ vấn đề lớn nào.
Tệp recentcomment.ts
src/plugins Tạo một tệp mới trong thư mục recentcomment.ts và nhập nội dung sau ( lưu ý những phần cần thay thế ):
/** * Lấy và xử lý dữ liệu bình luận mới nhất * Lấy bình luận mới nhất thông qua Waline API và định dạng hiển thị */
// Định nghĩa interface cho dữ liệu bình luậninterface WalineComment { nick: string; // Tên hiệu người bình luận comment: string; // Nội dung bình luận url: string; // URL trang bình luận avatar: string; // URL avatar time: number; // Timestamp thời gian bình luận like?: number; // Số lượt thích addr?: string; // Địa chỉ}
// Định nghĩa interface cho phản hồi APIinterface WalineResponse { data: WalineComment[];}
/** * Lấy dữ liệu bình luận mới nhất * @param limit Giới hạn số lượng bình luận * @returns Dữ liệu bình luận đã được định dạng */export async function fetchRecentComments(limit: number = 5): Promise<WalineComment[]> { try { // Địa chỉ backend Waline Hãy thay thế phần này bằng địa chỉ dịch vụ backend Waline bạn <!-- [!code highlight:2] --> const response = await fetch('https://<Waline Domain của bạn>/api/comment?type=recent'); if (!response.ok) { throw new Error(`Lấy bình luận thất bại: ${response.status}`); }
const data: WalineResponse = await response.json(); return data.data.slice(0, limit); } catch (error) { console.error('Lỗi khi lấy bình luận mới nhất:', error); return []; }}
/** * Định dạng thời gian bình luận * @param timestamp Timestamp * @returns Chuỗi thời gian đã định dạng */export function formatCommentTime(timestamp: number): string { const date = new Date(timestamp); const now = new Date(); const diff = now.getTime() - date.getTime();
// Trong vòng một phút if (diff < 60 * 1000) { return 'Vừa xong'; }
// Trong vòng một giờ if (diff < 60 * 60 * 1000) { return `${Math.floor(diff / (60 * 1000))} phút trước`; }
// Trong vòng một ngày if (diff < 24 * 60 * 60 * 1000) { return `${Math.floor(diff / (60 * 60 * 1000))} giờ trước`; }
// Trong vòng một tuần if (diff < 7 * 24 * 60 * 60 * 1000) { return `${Math.floor(diff / (24 * 60 * 60 * 1000))} ngày trước`; }
// Các trường hợp khác hiển thị ngày cụ thể return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;}
/** * Làm sạch thẻ HTML * @param html Chuỗi HTML * @returns Văn bản thuần đã được làm sạch */export function stripHtml(html: string): string { // Sử dụng biểu thức chính quy thay thế thao tác DOM, có thể chạy ở phía server return html.replace(/<[^>]*>/g, '');}
/** * Cắt ngắn văn bản * @param text Văn bản gốc * @param length Độ dài tối đa * @returns Văn bản đã được cắt ngắn */export function truncateText(text: string, length: number = 100): string { if (text.length <= length) return text; return text.substring(0, length) + '...';}Tệp rc.css
src/assets/styles Tạo một tệp mới trong thư mục rc.css và điền nội dung sau vào:
/* Kiểu thành phần bình luận mới nhất */.recent-comments { background-color: hsl(var(--background) / var(--un-bg-opacity, 1)); border: 1px solid hsl(var(--border) / var(--un-border-opacity, 1)); border-radius: var(--radius); padding: 1rem; margin-bottom: 1.5rem; margin-top: 0; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);}
.recent-comments-title { font-size: 1.2rem; font-weight: 500; margin-bottom: 1rem; color: hsl(var(--foreground) / var(--un-text-opacity, 1)); display: flex; align-items: center; gap: 0.5rem;}
.recent-comments-title svg { width: 1.2rem; height: 1.2rem;}
.comment-list { display: flex; flex-direction: column; gap: 1rem;}
.comment-item { display: flex; gap: 0.75rem; padding-bottom: 1rem; border-bottom: 1px solid hsl(var(--border) / 0.5);}
.comment-item:last-child { border-bottom: none; padding-bottom: 0;}
.comment-avatar { width: 2.5rem; height: 2.5rem; border-radius: 50%; overflow: hidden; flex-shrink: 0;}
.comment-avatar img { width: 100%; height: 100%; object-fit: cover;}
.comment-content { flex: 1; min-width: 0;}
.comment-meta { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.25rem;}
.comment-author { font-weight: 500; color: hsl(var(--foreground) / var(--un-text-opacity, 1)); font-size: 0.9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;}
.comment-time { font-size: 0.8rem; color: hsl(var(--muted-foreground) / var(--un-text-opacity, 1));}
.comment-text { font-size: 0.9rem; color: hsl(var(--muted-foreground) / var(--un-text-opacity, 1)); line-height: 1.5; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; word-break: break-word;}
.comment-link { display: block; font-size: 0.8rem; color: hsl(var(--primary) / var(--un-text-opacity, 1)); margin-top: 0.25rem; text-decoration: none; transition: opacity 0.2s;}
.comment-link:hover { opacity: 0.8;}
.comment-empty { text-align: center; padding: 1rem 0; color: hsl(var(--muted-foreground) / var(--un-text-opacity, 1)); font-size: 0.9rem;}
/* Thiết kế đáp ứng */@media (max-width: 768px) { .comment-avatar { width: 2rem; height: 2rem; }
.comment-author { font-size: 0.85rem; }
.comment-time { font-size: 0.75rem; }
.comment-text { font-size: 0.85rem; -webkit-line-clamp: 2; }}Tệp RecentComments.astro
src/components Tạo một tệp mới trong thư mục RecentComments.astro và nhập nội dung sau:
---import { fetchRecentComments, formatCommentTime, stripHtml, truncateText } from '@/plugins/recentcomment';import { Icon } from 'astro/user';
// Lấy dữ liệu bình luận mới nhấtconst comments = await fetchRecentComments(5);---
<div class="recent-comments"> <div class="recent-comments-title"> <Icon name="list" /> <span>Bình luận mới nhất</span> </div>
<div class="comment-list"> {comments.length > 0 ? ( comments.map((comment) => ( <div class="comment-item"> <div class="comment-avatar"> <img src={comment.avatar} alt={comment.nick} loading="lazy" /> </div> <div class="comment-content"> <div class="comment-meta"> <span class="comment-author">{comment.nick}</span> <span class="comment-time">{formatCommentTime(comment.time)}</span> </div> <div class="comment-text" set:html={truncateText(stripHtml(comment.comment), 100)} /> <a href={comment.url ? comment.url.replace(/\/$/, '') : '#'} class="comment-link">Xem chi tiết →</a> </div> </div> )) ) : ( <div class="comment-empty">Chưa có dữ liệu bình luận</div> )} </div></div>
<script> // Dọn dẹp thẻ HTML phía client document.addEventListener('astro:page-load', () => { const commentTexts = document.querySelectorAll('.comment-text'); commentTexts.forEach(element => { // Đảm bảo liên kết mở trong cửa sổ mới const links = element.querySelectorAll('a'); links.forEach(link => { link.setAttribute('target', '_blank'); link.setAttribute('rel', 'noopener noreferrer'); }); }); });</script>
<style is:global> @import '@/assets/styles/rc.css';</style>Sử dụng
Thêm src/pages/index.astro nội dung sau vào tệp:
---import RecentComments from '@/components/RecentComments.astro' //Nhập thành phần # [!code ++]---
<PageLayout meta={{ title: 'Home' }} highlightColor='#FFF8DC'> <main class='flex w-full flex-col items-center'> <div id='content' class='animate flex flex-col md:flex-row gap-y-10 md:gap-x-6 md:w-4/5 lg:w-5/6'> <!--RecentComments--> <div class='md:w-1/3 md:mt-0'> # [!code ++] <RecentComments /> # [!code ++] </div> # [!code ++] <!--RecentComments--> </div> <Quote class='mt-12' /> </main></PageLayout>Giảm thiểu việc sử dụng
---import RecentComments from '@/components/RecentComments.astro'---
<RecentComments />Ủng Hộ & Chia Sẻ
Nếu bài viết này giúp ích cho bạn, hãy chia sẻ hoặc ủng hộ nhé!
Hiển thị bình luận mới nhất thông qua API Waline
https://thinhem.id.vn/posts/hien-thi-binh-luan-moi-nhat/ Bài Viết Liên Quan Thông Minh
1
Share Code Trang Trí Website Đón Tết
Blog công nghệ Nhân dịp Tết sắp đến, thêm không khí vui tươi cho website với 2 đèn lồng đỏ treo lủng lẳng góc trên bằng CSS thuần, nhẹ nhàng dễ dùng.
2
Nhật Ký chỉnh sửa Blog
Blog công nghệ Chia sẻ những thay đổi lớn khi nâng cấp theme: chỉnh giao diện desktop, xây hệ thống đăng ký bạn bè, tự động kiểm tra link và dọn dẹp tính năng thừa.
3
Cách Xây Dựng Blog Độc Lập
Tư duy Cá Nhân Blog này chia sẻ cách xây dựng blog độc lập, từ lựa chọn tên miền đến cấu trúc tĩnh và triển khai. Khám phá các phương pháp dễ bảo trì và lâu dài để tạo dựng không gian trực tuyến của riêng bạn.
4
Sơ đồ PlantUML trong Markdown
Hướng dẫn bài viết Bài viết mẫu dùng để kiểm tra khả năng render PlantUML, chuyển đổi theme và tương tác trong Blog.
5
Cách Tạo Hiệu Ứng Click Chuột Cho Website Astro/Blogger
Blog công nghệ Tìm hiểu cách tạo hiệu ứng click chuột đơn giản cho website Astro hoặc Blogger để tăng tính tương tác.
Bài Viết Ngẫu Nhiên Ngẫu Nhiên