import { useEffect, useMemo, useState } from 'react' import { Link } from 'wouter' interface Product { id: number name: string category: string price: number stock: number rating: number image: string description: string tags: string[] } const generateProducts = (count: number): Product[] => { const categories = ['手机', '电脑', '平板', '耳机', '手表', '相机'] const brands = ['Apple', 'Samsung', 'Huawei', 'Xiaomi', 'Sony', 'Dell'] const adjectives = ['Pro', 'Max', 'Ultra', 'Plus', 'Air', 'Mini'] return Array.from({ length: count }, (_, i) => ({ id: i + 1, name: `${brands[i % brands.length]} ${categories[i % categories.length]} ${adjectives[i % adjectives.length]}`, category: categories[i % categories.length], price: Math.floor(Math.random() * 10000) + 500, stock: Math.floor(Math.random() * 100), rating: Math.round((Math.random() * 2 + 3) * 10) / 10, image: `https://picsum.photos/200/200?random=${i}`, description: `这是一款优秀的${categories[i % categories.length]}产品,具有出色的性能和设计。`, tags: ['热销', '新品', '推荐'].slice(0, Math.floor(Math.random() * 3) + 1), })) } // Loading skeleton component const LoadingSkeleton = () => (
{Array.from({ length: 12 }, (_, i) => `skeleton-item-${i}`).map((id) => (
))}
) // Product card component const ProductCard = ({ product }: { product: Product }) => (
{product.name}
{product.tags.map((tag) => ( {tag} ))}

{product.name}

{product.description}

¥{product.price.toLocaleString()}
{product.rating}
库存: {product.stock} {product.category}
) // Product list item component const ProductListItem = ({ product }: { product: Product }) => (
{product.name}

{product.name}

{product.description}

{product.category} 库存: {product.stock}
{product.rating}
¥{product.price.toLocaleString()}
) // Pagination component interface PaginationProps { currentPage: number totalPages: number startIndex: number endIndex: number totalItems: number onPageChange: (page: number) => void } const Pagination = ({ currentPage, totalPages, startIndex, endIndex, totalItems, onPageChange, }: PaginationProps) => { const getPageNumbers = () => { const pages = [] const maxVisible = 5 let start = Math.max(1, currentPage - Math.floor(maxVisible / 2)) const end = Math.min(totalPages, start + maxVisible - 1) if (end - start + 1 < maxVisible) { start = Math.max(1, end - maxVisible + 1) } for (let i = start; i <= end; i++) { pages.push(i) } return pages } return (
显示 {startIndex + 1}-{Math.min(endIndex, totalItems)} 条, 共 {totalItems} 条结果
{getPageNumbers().map((page) => ( ))}
) } export default function ListTestPage() { const [products, setProducts] = useState([]) const [loading, setLoading] = useState(true) const [searchTerm, setSearchTerm] = useState('') const [selectedCategory, setSelectedCategory] = useState('全部') const [sortBy, setSortBy] = useState('name') const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc') const [currentPage, setCurrentPage] = useState(1) const [itemsPerPage, setItemsPerPage] = useState(12) const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid') const categories = ['全部', '手机', '电脑', '平板', '耳机', '手表', '相机'] // Helper to set filters and reset page const handleSearchChange = (term: string) => { setSearchTerm(term) setCurrentPage(1) } const handleCategoryChange = (category: string) => { setSelectedCategory(category) setCurrentPage(1) } const handleSortChange = (sort: string) => { setSortBy(sort) setCurrentPage(1) } const handleSortOrderChange = (order: 'asc' | 'desc') => { setSortOrder(order) setCurrentPage(1) } // 模拟数据加载 useEffect(() => { const loadData = async () => { setLoading(true) // 模拟网络延迟 await new Promise((resolve) => setTimeout(resolve, 1500)) const data = generateProducts(150) setProducts(data) setLoading(false) } loadData() }, []) // 搜索和过滤 - Use useMemo to compute filtered products const filteredProducts = useMemo(() => { let filtered = [...products] // 按类别过滤 if (selectedCategory !== '全部') { filtered = filtered.filter((product) => product.category === selectedCategory) } // 按搜索词过滤 if (searchTerm) { filtered = filtered.filter( (product) => product.name.toLowerCase().includes(searchTerm.toLowerCase()) || product.description.toLowerCase().includes(searchTerm.toLowerCase()) ) } // 排序 filtered.sort((a, b) => { let aValue: any = a[sortBy as keyof Product] let bValue: any = b[sortBy as keyof Product] if (typeof aValue === 'string') { aValue = aValue.toLowerCase() bValue = bValue.toLowerCase() } if (sortOrder === 'asc') { return aValue > bValue ? 1 : -1 } else { return aValue < bValue ? 1 : -1 } }) return filtered }, [products, searchTerm, selectedCategory, sortBy, sortOrder]) // 分页计算 const totalPages = Math.ceil(filteredProducts.length / itemsPerPage) const startIndex = (currentPage - 1) * itemsPerPage const endIndex = startIndex + itemsPerPage const currentProducts = filteredProducts.slice(startIndex, endIndex) const handlePageChange = (page: number) => { setCurrentPage(page) // 滚动到顶部 window.scrollTo({ top: 0, behavior: 'smooth' }) } return (

产品列表测试

测试搜索、过滤、排序、分页和滚动功能

{/* 搜索和过滤栏 */}
{/* 搜索框 */}
handleSearchChange(e.target.value)} placeholder="输入产品名称或描述..." className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white" />
{/* 类别过滤 */}
{/* 排序方式 */}
{/* 排序顺序 */}
{/* 视图控制 */}
每页显示:
视图:
{/* 产品列表 */} {loading ? ( ) : filteredProducts.length === 0 ? (
🔍

没有找到匹配的产品

请尝试调整搜索条件或过滤器

) : ( <> {viewMode === 'grid' ? (
{currentProducts.map((product: Product) => ( ))}
) : (
{currentProducts.map((product: Product) => ( ))}
)} )} {/* 返回顶部按钮 */} {/* 返回链接 */}
← 返回测试页面列表
) }