自助下单网站设计方案
基于您的需求,我设计了一个现代化的自助下单网站,具有直观的用户界面、流畅的购物体验和响应式设计,网站包含商品展示、购物车管理、结算流程和订单确认等核心功能,采用清新的蓝色为主色调,搭配橙色作为交互元素,营造专业且友好的购物氛围。

以下是完整的实现代码:
import React, { useState, createContext, useContext, useEffect } from 'react';
import { BrowserRouter as Router, Routes, Route, Link, useParams, useNavigate } from 'react-router-dom';
// 购物车上下文
const CartContext = createContext();
const CartProvider = ({ children }) => {
const [cartItems, setCartItems] = useState([]);
// 添加商品到购物车
const addToCart = (product, quantity = 1) => {
setCartItems(prevItems => {
const existingItem = prevItems.find(item => item.id === product.id);
if (existingItem) {
return prevItems.map(item =>
item.id === product.id
? {...item, quantity: item.quantity + quantity}
: item
);
} else {
return [...prevItems, {...product, quantity}];
}
});
};
// 更新商品数量
const updateQuantity = (id, quantity) => {
if (quantity < 1) return;
setCartItems(prevItems =>
prevItems.map(item =>
item.id === id ? {...item, quantity} : item
)
);
};
// 删除购物车中的商品
const removeFromCart = (id) => {
setCartItems(prevItems => prevItems.filter(item => item.id !== id));
};
// 清空购物车
const clearCart = () => {
setCartItems([]);
};
// 计算购物车总金额
const getTotalAmount = () => {
return cartItems.reduce((total, item) => total + (item.price * item.quantity), 0).toFixed(2);
};
// 购物车商品总数
const getTotalItems = () => {
return cartItems.reduce((total, item) => total + item.quantity, 0);
};
return (
<CartContext.Provider value={{
cartItems,
addToCart,
updateQuantity,
removeFromCart,
clearCart,
getTotalAmount,
getTotalItems
}}>
{children}
</CartContext.Provider>
);
};
// 自定义hook获取购物车上下文
const useCart = () => useContext(CartContext);
// 模拟商品数据
const products = [
{
id: 1,
name: "无线蓝牙耳机",
price: 199.99,
description: "高清音质,降噪功能,续航24小时",
image: "https://picsum.photos/seed/headphone/300/300"
},
{
id: 2,
name: "智能手表",
price: 299.99,
description: "心率监测,睡眠分析,防水设计",
image: "https://picsum.photos/seed/watch/300/300"
},
{
id: 3,
name: "便携式充电宝",
price: 59.99,
description: "20000mAh大容量,双向快充",
image: "https://picsum.photos/seed/powerbank/300/300"
},
{
id: 4,
name: "机械键盘",
price: 129.99,
description: "青轴机械键盘,RGB背光,全键无冲",
image: "https://picsum.photos/seed/keyboard/300/300"
},
{
id: 5,
name: "平板电脑",
price: 499.99,
description: "10.2英寸屏幕,64GB存储,高清显示",
image: "https://picsum.photos/seed/tablet/300/300"
},
{
id: 6,
name: "运动手环",
price: 89.99,
description: "计步,睡眠监测,防水,长续航",
image: "https://picsum.photos/seed/bracelet/300/300"
}
];
// 头部组件
const Header = () => {
const { getTotalItems } = useCart();
const navigate = useNavigate();
return (
<header className="bg-blue-600 text-white shadow-md">
<div className="container mx-auto px-4 py-3 flex justify-between items-center">
<h1 className="text-2xl font-bold cursor-pointer" onClick={() => navigate('/')}>自助下单平台</h1>
<nav className="hidden md:flex space-x-6">
<Link to="/" className="hover:text-blue-200 transition-colors">首页</Link>
<Link to="/products" className="hover:text-blue-200 transition-colors">商品列表</Link>
</nav>
<div className="relative">
<button onClick={() => navigate('/cart')} className="flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" />
</svg>
<span className="ml-2">购物车</span>
<span className="absolute -top-2 -right-2 bg-red-500 text-white text-xs rounded-full w-5 h-5 flex items-center justify-center">
{getTotalItems()}
</span>
</button>
</div>
</div>
</header>
);
};
// 页脚组件
const Footer = () => {
return (
<footer className="bg-gray-800 text-white py-6 mt-12">
<div className="container mx-auto px-4">
<div className="flex flex-col md:flex-row justify-between items-center">
<p className="mb-4 md:mb-0">© 2025 自助下单平台. 保留所有权利.</p>
<div className="flex space-x-4">
<a href="#" className="hover:text-blue-300 transition-colors">关于我们</a>
<a href="#" className="hover:text-blue-300 transition-colors">联系我们</a>
<a href="#" className="hover:text-blue-300 transition-colors">隐私政策</a>
</div>
</div>
</div>
</footer>
);
};
// 商品卡片组件
const ProductCard = ({ product }) => {
const { addToCart } = useCart();
const navigate = useNavigate();
return (
<div className="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300">
<div className="h-48 overflow-hidden">
<img
src={product.image}
alt={product.name}
className="w-full h-full object-cover hover:scale-105 transition-transform duration-500"
onClick={() => navigate(`/product/${product.id}`)}
/>
</div>
<div className="p-4">
<h3 className="font-bold text-lg mb-2 hover:text-blue-600 cursor-pointer" onClick={() => navigate(`/product/${product.id}`)}>
{product.name}
</h3>
<p className="text-gray-600 text-sm mb-3 line-clamp-2">{product.description}</p>
<div className="flex justify-between items-center">
<span className="text-blue-600 font-bold text-xl">${product.price.toFixed(2)}</span>
<button
onClick={() => addToCart(product)}
className="bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded transition-colors duration-300 flex items-center"
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
加入购物车
</button>
</div>
</div>
</div>
);
};
// 首页
const HomePage = () => {
const featuredProducts = products.slice(0, 4);
return (
<div className="container mx-auto px-4 py-8">
<div className="mb-8">
<h2 className="text-3xl font-bold mb-4">欢迎来到自助下单平台</h2>
<p className="text-gray-600 text-lg">选择您喜爱的商品,轻松下单,快速送达</p>
</div>
<div className="mb-12">
<h3 className="text-2xl font-bold mb-6">热门推荐</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
{featuredProducts.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
</div>
<div className="bg-blue-50 rounded-lg p-8 flex flex-col md:flex-row items-center justify-between">
<div className="mb-6 md:mb-0 md:mr-6">
<h3 className="text-2xl font-bold mb-2">购物更便捷</h3>
<p className="text-gray-600">简单几步,轻松完成购物流程,安全支付,快速配送</p>
</div>
<button onClick={() => window.scrollTo(0, 0)} className="bg-blue-600 hover:bg-blue-700 text-white py-3 px-6 rounded transition-colors duration-300 text-lg">
立即购物
</button>
</div>
</div>
);
};
// 商品列表页
const ProductsPage = () => {
return (
<div className="container mx-auto px-4 py-8">
<h2 className="text-3xl font-bold mb-6">全部商品</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
{products.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
</div>
);
};
// 商品详情页
const ProductDetailPage = () => {
const { id } = useParams();
const product = products.find(p => p.id === parseInt(id));
const { addToCart } = useCart();
if (!product) {
return <div className="container mx-auto px-4 py-8">商品不存在</div>;
}
return (
<div className="container mx-auto px-4 py-8">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<div className="h-96 overflow-hidden rounded-lg shadow-md">
<img src={product.image} alt={product.name} className="w-full h-full object-cover" />
</div>
<div>
<h2 className="text-3xl font-bold mb-2">{product.name}</h2>
<p className="text-blue-600 font-bold text-2xl mb-4">${product.price.toFixed(2)}</p>
<div className="mb-6">
<h3 className="text-xl font-bold mb-2">商品描述</h3>
<p className="text-gray-600">{product.description}</p>
</div>
<button
onClick={() => addToCart(product)}
className="bg-blue-600 hover:bg-blue-700 text-white py-3 px-6 rounded transition-colors duration-300 text-lg flex items-center"
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
加入购物车
</button>
</div>
</div>
<div className="mt-12">
<h3 className="text-2xl font-bold mb-4">您可能还喜欢</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
{products.filter(p => p.id !== product.id).slice(0, 4).map(p => (
<ProductCard key={p.id} product={p} />
))}
</div>
</div>
</div>
);
};
// 购物车页面
const CartPage = () => {
const { cartItems, updateQuantity, removeFromCart, getTotalAmount, clearCart } = useCart();
const navigate = useNavigate();
if (cartItems.length === 0) {
return (
<div className="container mx-auto px-4 py-8 text-center">
<h2 className="text-2xl font-bold mb-4">您的购物车是空的</h2>
<button onClick={() => navigate('/products')} className="bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded transition-colors duration-300">
去购物
</button>
</div>
);
}
return (
<div className="container mx-auto px-4 py-8">
<h2 className="text-3xl font-bold mb-6">购物车</h2>
<div className="overflow-x-auto">
<table className="w-full border-collapse">
<thead>
<tr className="bg-gray-100">
<th className="py-3 px-4 text-left">商品</th>
<th className="py-3 px-4 text-left">价格</th>
<th className="py-3 px-4 text-left">数量</th>
<th className="py-3 px-4 text-left">小计</th>
<th className="py-3 px-4 text-left">操作</th>
</tr>
</thead>
<tbody>
{cartItems.map(item => (
<tr key={item.id} className="border-b border-gray-200">
<td className="py-3 px-4">
<div className="flex items-center">
<img src={item.image} alt={item.name} className="w-12 h-12 object-cover mr-3" />
<span>{item.name}</span>
</div>
</td>
<td className="py-3 px-4">${item.price.toFixed(2)}</td>
<td className="py-3 px-4">
<div className="flex items-center">
<button
onClick={() => updateQuantity(item.id, item.quantity - 1)}
className="bg-gray-200 hover:bg-gray-300 w-8 h-8 flex items-center justify-center rounded-l transition-colors duration-300"
>
-
</button>
<span className="w-12 h-8 flex items-center justify-center border-t border-b border-gray-200">
{item.quantity}
</span>
<button
onClick={() => updateQuantity(item.id, item.quantity + 1)}
className="bg-gray-200 hover:bg-gray-300 w-8





