我不确定是否正确我认为错误是因为我期待来自 AJAX 请求的 JSON 响应,但是我收到的 HTML 响应不是正确的 JSON 格式。
1-products.php(这里有所有产品的详细信息)
<?php
$products = [
1 => ["name" => "Apple", "price" => 5.50, "image" => "book.png"],
2 => ["name" => "Mango", "price" => 15.00, "image" => "bag.png"],
3 => ["name" => "Orange", "price" => 18.55, "image" => "cloth.png"],
4 => ["name" => "Pear", "price" => 15.75, "image" => "pants.png"]
];
2-ajax-cart.php(所有功能包括结帐)
<?php
if (isset($_POST["req"])) {
// (A) INIT SHOPPING CART
session_start();
if (!isset($_SESSION["cartI"])) {
$_SESSION["cartI"] = []; // cart items
$_SESSION["cartC"] = 0; // total quantity
}
// (B) UPDATE CART COUNT
function ccount () {
$_SESSION["cartC"] = 0;
if (count($_SESSION["cartI"])!=0) {
foreach ($_SESSION["cartI"] as $id=>$qty) { $_SESSION["cartC"] += $qty; }
}
}
// (C) STANDARD SYSTEM RESPONSE
function respond ($status=1, $msg="OK") {
echo json_encode(["status"=>$status, "msg"=>$msg, "count" => $_SESSION["cartC"]]);
}
// (D) CART ACTIONS
switch ($_POST["req"]) {
// (D1) GET COUNT
case "count": respond(); break;
// (D2) ADD / CHANGE QUANTITY / REMOVE
// send id only to add item
// send id and qty to set quantity
// send id and 0 qty to remove item
case "set":
$max = 99; // max allowed quantity per item
$item = &$_SESSION["cartI"][$_POST["id"]];
if (isset($_POST["qty"])) { $item = $_POST["qty"]; }
else { if (isset($item)) { $item++; } else { $item = 1; } }
if ($item<=0) { unset($_SESSION["cartI"][$_POST["id"]]); }
if ($item > $max) { $item = $max; }
ccount(); respond(); break;
// (D3) NUKE
case "nuke":
$_SESSION["cartI"] = [];
$_SESSION["cartC"] = 0;
respond(); break;
// (D4) GET ALL ITEMS IN CART
case "get":
// (D4-1) CART IS EMPTY
if ($_SESSION["cartC"]==0) { respond(1, null); break; }
// (D4-2) GET PRODUCTS + FILTER ILLEGAL
require "1-products.php";
$items = [];
foreach ($_SESSION["cartI"] as $id=>$qty) {
if (isset($products[$id])) {
$items[$id] = $products[$id];
$items[$id]["qty"] = $qty;
} else {
$_SESSION["cartC"] -= $_SESSION["cartI"][$id];
unset($_SESSION["cartI"][$id]);
}
}
if ($_SESSION["cartC"]==0) { respond(1, null); break; }
respond(1, $items); break;
// (D5) CHECKOUT
case "checkout":
// (D5-1) CART IS EMPTY
if ($_SESSION["cartC"]==0) { respond(0, "Cart Empty"); break; }
// (D5-2) EMAIL TO ADMIN
require "1-products.php";
$to = "[email protected]";
$subject = "Order Received";
$body = "Name: " . $_POST["name"] . "\r\n";
$body .= "Email: " . $_POST["email"] . "\r\n";
foreach ($_SESSION["cartI"] as $id=>$qty) {
$body .= sprintf("%s X %s\r\n", $qty, $products[$id]["name"]);
}
if (mail($to, $subject, $body)) {
$_SESSION["cartI"] = [];
$_SESSION["cartC"] = 0;
respond();
} else { respond(0, "ERROR SENDING MAIL"); }
break;
}
}
3a-shop.css(主页的CSS代码)
/* (A) WHOLE PAGE */
* {
font-family: Arial, Helvetica, sans-serif;
box-sizing: border-box;
}
body {
padding: 0;
max-width: 1000px;
margin: 0 auto;
background: #ebebeb;
}
.button {
padding: 10px;
border: 0;
font-weight: 700;
color: #fff;
background: #b90909;
cursor: pointer;
}
/* (B) PRODUCTS + CART */
/* (B1) WRAPPER */
#wrap { position: relative; }
/* (B2) HEADER */
#head {
display: flex;
flex-direction: row-reverse;
align-items: center;
padding: 20px 10px;
font-size: 16px;
color: #fff;
background: #282828;
}
#iDummy, #iCart {
margin: 0 10px;
cursor: pointer;
}
#cCart {
font-weight: 700;
padding: 5px;
margin-left: 5px;
background: #951818;
}
/* (B3) PRODUCTS WRAPPER */
#products {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 20px; padding: 20px;
}
@media screen and (max-width:600px) {
#products { grid-template-columns: repeat(2, 1fr); }
}
/* (B4) PRODUCTS */
.pCell {
padding: 10px;
background: #fff;
}
.pImg {
width: 100%;
height: 150px;
padding: 10px 20px;
object-fit: contain;
}
.pName, .pPrice { margin: 5px 0; }
.pName { font-size: 1.3rem; }
.pPrice { font-size: 0.9rem; color: #686868; }
.pAdd { width: 100%; }
/* (B5) CART WRAPPER */
#wCart {
display: none;
position: absolute;
top: 0; left: 0; z-index: 999;
width: 320px; padding: 15px;
height: 100%; min-height: 100vh;
background: #f5f5f5;
border-right: 1px solid #a7a7a7;
border-left: 1px solid #a7a7a7;
}
#wCart.show { display: block; }
#wCartClose {
font-size: 20px;
background: #282828;
}
/* (B6) CART ITEMS */
.cCell {
display: flex;
align-items: stretch;
margin-bottom: 15px;
border: 1px solid #e3e3e3;
background: #fff;
}
.cCell.empty { padding: 10px; }
.cQty {
text-align: center;
width: 50px;
border: 0;
background: #e7e7e7;
}
.cInfo {
flex-grow: 1;
padding: 10px 5px;
}
.cName { font-weight: 700; }
.cPrice { font-size: 0.9rem; }
/* (C) CHECKOUT */
#checkout {
position: fixed;
top: 0; left: 0; z-index: 999;
width: 100vw; height: 100vh;
background: rgba(0, 0, 0, 0.8);
display: none;
align-items: center;
justify-content: center;
}
#checkout.show { display: flex; }
#checkout form {
position: relative;
width: 400px;
padding: 20px;
background: #fff;
}
#checkout label, #checkout input {
display: block;
width: 100%;
}
#checkout label { padding: 10px 0; }
#checkout input { padding: 10px; }
#checkout input[type=submit] { margin-top: 20px; }
#coClose {
position: absolute;
top: 0; right: 0;
}
3a-shop.php(主页在这里)
<!DOCTYPE html>
<html>
<head>
<title>Shopping Page Demo</title>
<meta charset="utf-8">
<link rel="stylesheet" href="3a-shop.css">
<script src="3b-cart.js"></script>
</head>
<body>
<!-- (A) PRODUCTS + SHOPPING CART -->
<div id="wrap">
<!-- (A1) HEADER -->
<div id="head">
<div id="iCart" onclick="cart.show()">
My Cart <span id="cCart">0</span>
</div>
</div>
<!-- (A2) PRODUCTS -->
<div id="products"><?php
require "1-products.php";
foreach ($products as $i=>$p) { ?>
<div class="pCell">
<img class="pImg" src="images/<?=$p["image"]?>">
<div class="pName"><?=$p["name"]?></div>
<div class="pPrice">$<?=$p["price"]?></div>
<input class="pAdd button" type="button" value="Add To Cart" onclick="cart.add(<?=$i?>)">
</div>
<?php } ?>
</div>
<!-- (A3) CART ITEMS -->
<div id="wCart">
<span id="wCartClose" class="button" onclick="cart.toggle(cart.hWCart, false)">⇦</span>
<h2>SHOPPING CART</h2>
<div id="cart"></div>
</div>
</div>
<!-- (B) CHECKOUT FORM -->
<div id="checkout"><form onsubmit="return cart.checkout()">
<div id="coClose" class="button" onclick="cart.toggle(cart.hCO, false)">X</div>
<label>Name</label>
<input type="text" id="coName" required value="Testing">
<label>Email</label>
<input type="email" id="coEmail" required value="[email protected]">
<input class="button" type="submit" value="Checkout">
</form></div>
</body>
</html>
3b-cart.js(用于购物车的 JavaScript)
var cart = {
// (A) HELPER - AJAX FETCH
ajax : (data, after) => {
// (A1) FORM DATA
let form = new FormData();
for (let [k, v] of Object.entries(data)) { form.append(k, v); }
// (A2) FETCH
fetch("2-ajax-cart.php", { method:"POST", body:form })
.then(res => res.json())
.then(res => {
if (res.status==1) { after(res); }
else { alert(res.msg); }
})
.catch(err => console.error(err));
},
// (B) HELPER - TOGGLE HTML SECTIONS
toggle : (target, show) => {
if (show) { target.className = "show"; }
else { target.className = ""; }
},
// (C) INITIALIZE
hCart : null, // html cart
hWCart : null, // html cart wrapper
hCCart : null, // html cart count
hCO : null, // html checkout wrapper
init : () => {
// (C1) GET HTML ELEMENTS
cart.hCart = document.getElementById("cart");
cart.hWCart = document.getElementById("wCart");
cart.hCCart = document.getElementById("cCart");
cart.hCO = document.getElementById("checkout");
// (C2) UPDATE CART COUNT
cart.ajax({ req : "count" }, res => cart.count(res.count));
},
// (D) UPDATE CART COUNT
count : qty => {
cart.hCCart.innerHTML = qty;
if (cart.hWCart.classList.contains("show")) { cart.show(); }
},
// (E) SHOW CART ITEMS
show : () => {
// (E1) RESET
cart.toggle(cart.hWCart, true);
cart.hCart.innerHTML = "";
// (E2) LOAD & GENERATE HTML
cart.ajax({ req : "get" }, items => {
// (E2-1) ITEMS IN CART
items = items.msg;
// (E2-2) CART IS EMPTY
if (items==null) {
cart.hCart.innerHTML = `<div class="cCell empty">Cart is empty</div>`;
}
// (E2-3) DRAW CART ITEMS
else {
let row, subtotal, total = 0;
for (let [id, item] of Object.entries(items)) {
// CALCULATE SUBTOTAL
subtotal = item["price"] * item["qty"];
total += subtotal;
// ITEM ROW
row = document.createElement("div");
row.className = "cCell";
row.innerHTML = `<input class="cQty" type="number" value="${item["qty"]}"
min="0" max="99" onchange="cart.change(${id}, this.value)">
<div class="cInfo">
<div class="cName">${item["name"]}</div>
<div class="cPrice">$${subtotal.toFixed(2)}</div>
</div>
<input class="cDel button" type="button" value="X" onclick="cart.remove(${id})">`;
cart.hCart.appendChild(row);
}
// CART TOTALS
row = document.createElement("div");
row.className = "cCell";
row.innerHTML = `<input class="cDel button" type="button" value="X" onclick="cart.empty()">
<div class="cInfo">
<div class="cName">Total</div>
<div class="cPrice">$${total.toFixed(2)}</div>
</div>
<input class="cDel button" type="button" value=">" onclick="cart.toggle(cart.hCO, true)">`;
cart.hCart.appendChild(row);
}
});
},
// (F) ADD ITEM TO CART
add : id => cart.ajax(
{ req : "set", id : id },
res => cart.count(res.count)
),
// (G) CHANGE ITEM QTY
change : (id, qty) => cart.ajax(
{ req : "set", id : id, qty : qty },
res => cart.count(res.count)
),
// (H) REMOVE ITEM
remove : id => cart.ajax(
{ req : "set", id : id, qty : 0 },
res => cart.count(res.count)
),
// (I) NUKE
empty : () => { if (confirm("Reset cart?")) {
cart.ajax(
{ req : "nuke" },
res => cart.count(res.count)
);
}},
// (J) CHECKOUT
checkout : () => {
cart.ajax({
req : "checkout",
name : document.getElementById("coName").value,
email : document.getElementById("coEmail").value
}, res => location.href = "3c-thank-you.html");
return false;
}
};
window.onload = cart.init;
3c-thank-you.html(感谢客户的简单页面)
<!DOCTYPE html>
<html>
<head>
<title>Done</title>
<meta charset="utf-8">
</head>
<body>
<h1>Thank You</h1>
<p>Order received.</p>
</body>
</html>
我不知道该怎么做请帮忙~~