目录
1.效果展示
2.分步演示
商品详情页面
搜索页
购物车页
结算页面
商品详情页
商品搜索页
购物车页
购物车详情页
结算页
在实际开发前要对我们所需要做的整体页面和其中所需要的各个组件有一个整体构思,此项目一共有三个页面:商品页面,购物车页面,结算界面。其中商品数据是每个页面都需要用到的所以将商品数据存于store里便于使用,其次使用React createPortal() 创建创建模态窗口或对话框之类的场景,即遮罩层和结算页面组件。最后对于移动端项目要设置视口的宽度确保在不同设备下完整显示。
视口宽度设置:
// 除以多少视口的宽度就是多少rem,现在设置视口的总宽度为750rem
document.documentElement.style.fontSize=100/750 + 'vw';
store下的商品数据:
import React from "react";
const CartContext=React.createContext({
items:[],
totalAmount:0,
totalPrice:0,
addItem:()=>{
},
removeItem:()=>{
},
clearCart:()=>{
}
});
export default CartContext;
index.html:
遮罩层Backdrop:
const backdropRoot=document.getElementById('backdrop-root')
const Backdrop=(props)=> {
return ReactDOM.createPortal(
{props.children}
,backdropRoot)
}
Meal.js:
页面的结构显示
const Meal=(props)=> {
return (
{props.meal.title}
{props.noDesc?null:{props.meal.desc}
}
{props.meal.price}
)
}
Meals.js:
const Meals=(props)=> {
return (
{props.mealsData.map(item=>
)}
)
}
Count.js:
商品计数加减
const Counter=(props)=> {
// 获取cartContext
const ctx=useContext(CartContext);
// 添加购物车的函数
const addButtonHandler=()=>{
ctx.addItem(props.meal)
}
const lessButtonHandler=()=>{
ctx.removeItem(props.meal)
}
return (
{
(props.meal.amount && props.meal.amount !==0) ? (
<>
{props.meal.amount}
>
) : null
}
)
};
App.js:
const App = () => {
// 创建一个state存储食物列表
const [mealsData, setMealsData] = useState(MEALS_DATA)
// 创建一个state,用来存储购物车的数据
const [cartData, setCartData] = useState({
// 商品
items: [],
// 商品总数
totalAmount: 0,
// 商品总价
totalPrice: 0
});
// 创建过滤Meals的函数
const filterHandler=(keyword)=>{
const newMealsData= MEALS_DATA.filter(item=>item.title.indexOf(keyword)!==- 1)
setMealsData(newMealsData)
}
// 想购物车中添加数据
const addItem = (meal) => {
// 对购物车进行复制
const newCart = { ...cartData };
// 判断购物车中是否有商品
if (newCart.items.indexOf(meal) === -1) {
// 将meal添加进购物车中
newCart.items.push(meal);
// 修改商品数量
meal.amount = 1
} else {
// 增加商品数量
meal.amount += 1;
}
// 增加总数
newCart.totalAmount += 1;
// 增加总金额
newCart.totalPrice += meal.price
setCartData(newCart)
}
// 减少商品数量
const removeItem = (meal) => {
const newCart = { ...cartData }
meal.amount -= 1;
// 检查商品数量是否为零
if (meal.amount === 0) {
// 从购物车中移除商品
newCart.items.splice(newCart.items.indexOf(meal), 1)
}
// 修改商品总数和总金额
newCart.totalAmount -= 1;
newCart.totalPrice -= meal.price;
setCartData(newCart)
}
// 清空购物车
const clearCart=()=>{
const newCart={...cartData}
// 将购物车中商品清零
newCart.items.forEach(item=>delete item.amount);
newCart.items=[];
newCart.totalAmount=0;
newCart.totalPrice=0;
setCartData(newCart)
}
};
FilterMeals.js:
const FilterMeals=(props)=> {
const inputChangeHandler=e=>{
const keyword=e.target.value.trim();
props.onFilter(keyword)
}
return (
)
}
cart.js:
购物车显示功能
// 购物车的组件
const Cart=()=> {
const ctx=useContext(CartContext);
// 添加一个state来设置详情页是否显示
const [showDetails,setShowDetails]=useState(false);
// 添加一个state设置结账页的显示与隐藏
const[showCheckout,setShowCheckout]=useState(false)
// 在组件每次重新渲染的时候,检查一下商品的总数量。如果数量为0,则修改showDetails为false
// 组件每次重新渲染,组件的函数体就会执行
useEffect(()=>{
if(ctx.totalAmount===0){
setShowDetails(false);
setShowCheckout(false)
}
},[ctx])
// 添加一个显示详情页的函数
const toggleDetailsHandler=()=>{
if(ctx.totalAmount===0) {
setShowDetails(false);
return
};
setShowDetails(preState=>!preState)
}
const showCheckoutHandler=()=>{
if(ctx.totalAmount===0) return;
setShowCheckout(true)
}
const hideCheckoutHandler=()=>{
setShowCheckout(false)
}
}
Confirm.js:
购物车商品清除功能
const Confirm=(props)=> {
return (
确认放弃秘制小汉堡吗?
)
}
CartDetails.js:
购物车结构显示
const CartDetails=()=> {
const ctx=useContext(CartContext)
// 设置state控制确认框的显示
const[showConfirm,setShowConfirm]=useState(false)
// 添加函数显示确认窗口
const showConfirmHandler=()=>{
setShowConfirm(true)
}
const cancelHandler=(e)=>{
e.stopPropagation();
setShowConfirm(false)
}
const OkHandler= ()=>{
// 清空购物车
ctx.clearCart();
}
return (
{showConfirm && }
e.stopPropagation()}
>
餐品详情
清空购物车
{
ctx.items.map(item=>
)
}
)
}
Bar.js:
底部栏的设置
const Bar=(props)=> {
return (
{props.totalPrice}
)
}
CheckoutItem.js:
结算页商品详情数据
const CheckoutItem=(props)=> {
return (
{props.meal.title}
{props.meal.price*props.meal.amount}
)
}
Checkout.js:
结算页面整体实现
const checkoutRoot=document.getElementById('checkout-root')
const Checkout=(props)=> {
const ctx=useContext(CartContext)
return ReactDOM.createPortal(
props.onHide()}
icon={faXmark}/>
餐品详情
{ctx.items.map(item=>)}
,checkoutRoot)
}