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/YouTube Origin Cho Google TV: Xem YouTube Không Quảng Cáo Trên Android TV
Nguyên nhân Cloudflare lỗi sập toàn cầu
Bài viết liên quanThông minh
1
Hướng dẫn mã hóa bài viết Astro Blog bằng SSR và API Authentication
Lập trình WebHướng dẫn bảo vệ nội dung Astro Blog bằng SSR, API Authentication và Cookie bảo mật. Tìm hiểu cách mã hóa bài viết, kiểm soát quyền truy cập và ẩn nội dung khỏi frontend.
2
Code Trang Trí Website Ngày Tết Bằng CSS: Tạo Đèn Lồng Đỏ Cho Blog Astro
Lập trình WebHướng dẫn thêm hiệu ứng đèn lồng đỏ trang trí website ngày Tết bằng CSS thuần. Chia sẻ code HTML và CSS nhẹ, dễ tích hợp cho blog Astro, website cá nhân và trang web công nghệ.
3
Cách Thêm Hiệu Ứng Click Chuột Cho Website Astro Và Blogger Bằng CSS JavaScript
Lập trình WebHướng dẫn tạo hiệu ứng click chuột cho website Astro và Blogger bằng CSS, JavaScript. Tăng tương tác người dùng với hiệu ứng con trỏ, animation và tùy chỉnh giao diện blog.
4
Nhật Ký Nâng Cấp Blog Astro: Tối Ưu Theme, Liên Kết Bạn Bè Và Hiệu Suất Website
Nhật Ký Xây Dựng WebsiteChia sẻ quá trình nâng cấp blog Astro: tối ưu giao diện desktop, xây dựng hệ thống liên kết bạn bè tự động, kiểm tra backlink, cải thiện hiệu suất và dọn dẹp tính năng không cần thiết.
5
Biểu đồ Mermaid trong Markdown
Lập trình WebVí dụ đơn giản về bài viết Markdown có sử dụng Mermaid.
Bài viết ngẫu nhiênNgẫu nhiên

























