需求分析:
列表頁(yè)list.html
html結(jié)構(gòu)
<p class="login-txt">登錄</p>
<p> <a href="register.html">注冊(cè)</a></p>
<p><a href="./shopCart.html">購(gòu)物車</a></p>
<div id="box">
<ul>
</ul>
</div>
<div class="mask">
<div class="login">
<p><input type="text" class="user"/></p>
<p><input type="text" class="pw"/></p>
<p><button>登錄</button>></p>
</div>
</div>
<script src="js/axios.js"></script>
<script src="js/jquery.js"></script>
<script src="js/jquery.cookie.js"></script>
<script src="js/list.js"></script>
<script src="js/addCart.js"></script>
<script src="js/login.js"></script>
列表頁(yè)功能一: 初始化展示商品列表
前端代碼
let page = 1; //頁(yè)碼
let mask = document.querySelector(".mask") //獲取dom
// 渲染數(shù)據(jù)
function render(data) {
if (data.code === 0) {
let html = ''
data.list.forEach((item) => {
html += `
<li>
<a href="./detail.html?id=${item.Id}">
<div class="pro_img"><img src="https:${item.imgUrl}" width="150" height="150"></div>
<h3 class="pro_name"><a href="#"> ${item.title} </a></h3>
<p class="pro_price">${item.price}元</p>
<p></p>
<div class="add_btn" data-id="${item.Id}">加入購(gòu)物車</div>
</a>
</li>
`
})
$("#box ul").append(html)
}
}
// 初始化加載數(shù)據(jù)
function initData() {
axios.get("/product",{
params: {
page
}
})
.then((res) => {
render(res.data)
})
}
initData()
后端代碼
// 查詢所有商品(分頁(yè)顯示)
router.get("/product", (req, res) => {
let { page } = req.query;
const pageSize = 10;
let start = (page - 1) * pageSize
let sql = `select * from midata order by Id asc limit ?,?`
conn.query(sql, [start, pageSize], function (err, result) {
if (err) {
console.log('查詢數(shù)據(jù)庫(kù)失敗');
} else {
let data;
if (result.length) {
data = {
code: 0,
list: result
}
} else {
data = {
code: 1,
msg: '沒(méi)有結(jié)果 '
}
}
res.send(data)
}
})
})
列表頁(yè)功能二: 登錄入口介汹,可在本頁(yè)面顯示登錄窗口,實(shí)現(xiàn)登錄功能
// 每個(gè)頁(yè)面中的登錄
function login() {
$(".mask button").on("click", function () {
let data = {
user: $(".user").val(),
pw: $(".pw").val()
}
axios.post('/login', data)
.then((res) => {
console.log(res.data);
mask.classList.remove("active")
$.cookie("user",data.user,{ expires: 100})
})
})
}
//登錄彈窗
function loginBox() {
let loginTxt = document.querySelector(".login-txt")
var login = document.querySelector(".login")
//綁定事件舶沛,單擊登錄時(shí)嘹承,顯示彈窗
loginTxt.onclick = function () {
mask.classList.add("active")
}
//單擊遮罩層,讓遮罩層消失
mask.onclick = function () {
this.classList.remove("active")
}
//阻止冒泡
login.onclick = function (e) {
e.stopPropagation()
}
}
login()
loginBox()
列表頁(yè)功能三: 每個(gè)商品實(shí)現(xiàn)加入購(gòu)物車功能
先驗(yàn)證是否登錄如庭,如何沒(méi)有登錄叹卷,進(jìn)行登錄,如果已登錄,則把商品id和用戶id傳向后端接口
前端代碼
function cart() {
// 加入購(gòu)物車
function addCart() {
$("#box ul").on("click", ".add_btn", function () {
//驗(yàn)證用戶是否登錄
let userId = $.cookie("user");
let proId = $(this).data("id") //獲取商品Id
console.log(proId);
if (!userId) {
//當(dāng)cookie不存在骤竹,即沒(méi)有登錄
mask.classList.add("active")
return;
}
let data = {
userId,
proId
}
axios.post("/cart",data)
.then((res)=>{
console.log(res.data);
})
})
}
addCart();
}
cart()
后端代碼
// 添加商品到購(gòu)物車
router.post("/cart", (req, res) => {
//接收參數(shù)
let { userId, proId } = req.body;
let sql = "select * from cart where userId = ? and proId = ?"
conn.query(sql, [userId, proId], function (err, result) {
if (err) {
console.log('數(shù)據(jù)庫(kù)訪問(wèn)失敗');
} else {
let data;
if (result.length) {
console.log('11');
//當(dāng)前用戶存在該商品
let cartId = result[0].cartId
let num = result[0].num + 1
// 更新商品數(shù)量
let sql = "update cart set num = ? where cartId = ?"
conn.query(sql, [num, cartId], function (err, result) {
if (result.affectedRows === 1) {
res.send({
code: 0,
msg: '添加購(gòu)物車成功帝牡,數(shù)量更改'
})
}
})
} else {
console.log(22);
//當(dāng)前用戶不存在該商品
let sql = "insert into cart (userId,proId,num) values (?,?,?)"
conn.query(sql, [userId, proId, 1], function (err, result) {
if (result.affectedRows === 1) {
res.send({
code: 0,
msg: '添加購(gòu)物車成功,數(shù)量初始為1'
})
}
})
}
}
})
})
列表頁(yè)功能四: 加入購(gòu)物車
后端接口接收商品id和用戶id蒙揣,先驗(yàn)證該用戶的當(dāng)前商品是否存在靶溜,如果不存在,則新增懒震,如果存在罩息,則修改數(shù)量
前端代碼
function cart() {
// 加入購(gòu)物車
function addCart() {
$("#box ul").on("click", ".add_btn", function () {
//驗(yàn)證用戶是否登錄
let userId = $.cookie("user");
let proId = $(this).data("id") //獲取商品Id
console.log(proId);
if (!userId) {
//當(dāng)cookie不存在,即沒(méi)有登錄
mask.classList.add("active")
return;
}
let data = {
userId,
proId
}
axios.post("/cart",data)
.then((res)=>{
console.log(res.data);
})
})
}
addCart();
}
cart()
后端代碼
// 添加商品到購(gòu)物車
router.post("/cart", (req, res) => {
//接收參數(shù)
let { userId, proId } = req.body;
let sql = "select * from cart where userId = ? and proId = ?"
conn.query(sql, [userId, proId], function (err, result) {
if (err) {
console.log('數(shù)據(jù)庫(kù)訪問(wèn)失敗');
} else {
let data;
if (result.length) {
console.log('11');
//當(dāng)前用戶存在該商品
let cartId = result[0].cartId
let num = result[0].num + 1
// 更新商品數(shù)量
let sql = "update cart set num = ? where cartId = ?"
conn.query(sql, [num, cartId], function (err, result) {
if (result.affectedRows === 1) {
res.send({
code: 0,
msg: '添加購(gòu)物車成功个扰,數(shù)量更改'
})
}
})
} else {
console.log(22);
//當(dāng)前用戶不存在該商品
let sql = "insert into cart (userId,proId,num) values (?,?,?)"
conn.query(sql, [userId, proId, 1], function (err, result) {
if (result.affectedRows === 1) {
res.send({
code: 0,
msg: '添加購(gòu)物車成功扣汪,數(shù)量初始為1'
})
}
})
}
}
})
})
列表頁(yè)功能五: 跳轉(zhuǎn)至詳情頁(yè)
單擊商品,跳轉(zhuǎn)到詳情頁(yè)锨匆,并傳遞當(dāng)前商品id
前端代碼
<a href="./detail.html?id=${item.Id}">商品</a>
詳情頁(yè): detail.html
詳情頁(yè)功能一: 初始化獲取商品id, 請(qǐng)求后端接口崭别,獲取商品信息并渲染
前端代碼
// 獲取Id
function getId(){
let search = location.search; // "?id=100"
let result = search.match(/^\?id=(\d+)$/)
let id = result[1];
return id
}
//渲染數(shù)據(jù)
function render(res){
if (res.data.code === 0) {
let item = res.data.list[0]
let html = ''
html += `
<li>
<a href="./detail.html?id=${item.Id}">
<div class="pro_img"><img src="https:${item.imgUrl}" width="150" height="150"></div>
<h3 class="pro_name"><a href="#"> ${item.title} </a></h3>
<p class="pro_price">${item.hot}元</p>
<div class="add_btn" data-id="${item.Id}">加入購(gòu)物車</div>
</a>
</li>
`
$("#box ul").append(html)
}
}
//獲取指定id對(duì)應(yīng)的商品信息
function getProduct() {
let id = getId()
axios.get(`/product/${id}`)
.then((res) => {
render(res)
})
}
getProduct()
后端代碼
router.get("/product/:id", (req, res) => {
let { id } = req.params;
let sql = `select * from midata where id = ?`
conn.query(sql, [id], function (err, result) {
if (err) {
console.log('查詢數(shù)據(jù)庫(kù)失敗');
} else {
let data;
if (result.length) {
data = {
code: 0,
list: result
}
} else {
data = {
code: 1,
msg: '沒(méi)有結(jié)果 '
}
}
res.send(data)
}
})
})
詳情頁(yè)功能二: 加入購(gòu)物車功能,邏輯參考列表頁(yè)功能
購(gòu)物車 shopCart.html
購(gòu)物車功能一: 初始化請(qǐng)求后臺(tái)接口恐锣,并傳遞當(dāng)前用戶id, 請(qǐng)求該用戶的所有購(gòu)物信息并展示
前端代碼
// 查看用戶是否登錄
function checkIsLogin(userId) {
if (!userId) return;
//登錄過(guò)
$("h1").addClass("hide")
$(".car").removeClass("hide")
}
//渲染數(shù)據(jù)
function render(res) {
if (res.data.code == 0) {
let html = ""
res.data.list.forEach((item) => {
html += `
<div class="row hid">
<div class="check left"> <input type="checkbox" class="select"></div>
<div class="img left"><img src="img/03-car-02.png" width="80" height="80"></div>
<div class="name left"><span> ${item.title} </span></div>
<div class="price left"><span>${item.price}元</span></div>
<div class="item_count_i">
<div class="num_count">
<div class="count_d" data-id="${item.cartId}">-</div>
<div class="c_num">${item.num}</div>
<div class="count_i" data-id="${item.cartId}">+</div>
</div>
</div>
<div class="subtotal left"><span>${item.price * item.num}元</span></div>
<div class="ctrl left"><a href="javascript:;" data-id="${item.cartId}">×</a></div>
</div>
`
})
$(".list").html(html)
}
}
// 請(qǐng)求購(gòu)物車列表數(shù)據(jù)
function loadData() {
let userId = $.cookie("user")
checkIsLogin(userId)
// 請(qǐng)求數(shù)據(jù)
axios.get("/cart", {
params: {
userId
}
})
.then((res) => {
render(res)
})
}
后端代碼
//查詢購(gòu)物車信息
router.get("/cart", (req, res) => {
let { userId } = req.query;
let sql = `select * from cart,midata where cart.userId = ? and cart.proId = midata.Id order by cart.cartId desc`
conn.query(sql, [userId], function (err, result) {
if (err) {
console.log('查詢數(shù)據(jù)庫(kù)失敗');
} else {
let data;
if (result.length) {
data = {
code: 0,
list: result
}
} else {
data = {
code: 1,
msg: '沒(méi)有結(jié)果 '
}
}
res.send(data)
}
})
})
購(gòu)物車功能二: 復(fù)選框全選的單擊事件: 選中時(shí)茅主,所有商品也要選中,取消選擇時(shí)土榴,所有商品也取消選擇. 同時(shí)計(jì)算總價(jià)
計(jì)算總價(jià)
let total = 0; //總價(jià)
//計(jì)算總價(jià)
function getTotal() {
total = 0;
[...$(".list .select")].forEach((item) => {
if ($(item).prop("checked")) {
let subTotal = parseFloat($(item).parent().parent().find(".subtotal span").text())
total += subTotal
}
})
$("#sum_area #price_num").text(total)
}
前端代碼
// 全選功能
function checkAll() {
$(".check-all").on("click", function () {
let selected = $(this).prop("checked")
$(".list .select").prop("checked", selected)
getTotal()
})
}
購(gòu)物車功能三. 每個(gè)商品復(fù)選框的單擊事件: 單擊時(shí)诀姚,要遍歷所有商品的選中狀態(tài),都被選中玷禽,則選中“全選”復(fù)選框赫段,都取消選中,則取消“全選”復(fù)選框矢赁。 同時(shí)計(jì)算總價(jià)
前端代碼
//切換某一個(gè)商品的選擇狀態(tài)
function toggleOne() {
$(".list").on("click", ".select", function () {
let selected = $(this).prop("checked")
if (selected) {
let flag = [...$(".list .select")].every((item) => {
return $(item).prop("checked")
})
if (flag) {
$(".check-all").prop("checked", true)
}
} else {
$(".check-all").prop("checked", false)
}
getTotal()
})
}
購(gòu)物車功能四. 加減數(shù)量: 獲取原有數(shù)量糯笙,加或減后,調(diào)用后端接口撩银,傳遞數(shù)量给涕,CartId, 后端則把對(duì)應(yīng)購(gòu)物車信息的數(shù)量進(jìn)行更新。 前端接收到更新成功后额获,計(jì)算小計(jì)價(jià)格够庙,并同時(shí)計(jì)算總價(jià)
前端代碼
//改變數(shù)量
function changeNum(el, type) {
$(".list").on("click", el, function () {
let num = $(this).siblings(".c_num").text()
type === 'add' ? num++ : num--
//后端接口
let data = {
cartId: $(this).data("id"),
num
}
axios.put("/cart", data)
.then((res) => {
//前端
$(this).parent().parent().siblings(".check").children(".select").prop("checked", true);
let price = parseFloat($(this).parent().parent().siblings(".price").children("span").text())
$(this).siblings(".c_num").text(num)
let subTotal = num * price
$(this).parent().parent().siblings(".subtotal").children("span").text(subTotal)
getTotal()
})
})
}
后端代碼
//修改商品數(shù)量
router.put("/cart", (req, res) => {
//接收參數(shù)
let { cartId, num } = req.body;
let sql = "update cart set num = ? where cartId = ?"
conn.query(sql, [num, cartId], function (err, result) {
if (err) {
console.log('數(shù)據(jù)庫(kù)訪問(wèn)失敗');
} else {
if (result.affectedRows === 1) {
res.send({
code: 0,
msg: '添加購(gòu)物車成功,數(shù)量更改'
})
}
}
})
})
購(gòu)物車功能五: 刪除: 調(diào)用后端接口抄邀,傳遞CartId, 在后端刪除指定CartId的信息耘眨,前端接收到成功刪除后,再次到后端請(qǐng)求當(dāng)前用戶所有購(gòu)物車信息并渲染
前端代碼
// 刪除購(gòu)物車信息
function delCart() {
$(".list").on("click", ".ctrl a", function () {
let cartId = $(this).data("id")
axios.delete(`/cart/${cartId}`)
.then((res) => {
loadData()
})
})
}
后端代碼
//刪除購(gòu)物車信息
router.delete("/cart/:cartId", (req, res) => {
let { cartId } = req.params;
let sql = `delete from cart where cartId = ?`
conn.query(sql, [cartId], function (err, result) {
if (err) {
console.log('查詢數(shù)據(jù)庫(kù)失敗');
} else {
let data;
if (result.affectedRows === 1) {
data = {
code: 0,
msg: '刪除成功'
}
}
res.send(data)
}
})
})