12-Express+Jquery實(shí)現(xiàn)購(gòu)物車前后端

需求分析:

列表頁(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)
        }
    })
})
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末境肾,一起剝皮案震驚了整個(gè)濱河市剔难,隨后出現(xiàn)的幾起案子胆屿,更是在濱河造成了極大的恐慌,老刑警劉巖钥飞,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異衫嵌,居然都是意外死亡读宙,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門楔绞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)结闸,“玉大人,你說(shuō)我怎么就攤上這事酒朵¤氤” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵蔫耽,是天一觀的道長(zhǎng)结耀。 經(jīng)常有香客問(wèn)我,道長(zhǎng)匙铡,這世上最難降的妖魔是什么图甜? 我笑而不...
    開(kāi)封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮鳖眼,結(jié)果婚禮上黑毅,老公的妹妹穿的比我還像新娘。我一直安慰自己钦讳,他們只是感情好矿瘦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著愿卒,像睡著了一般缚去。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上琼开,一...
    開(kāi)封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天病游,我揣著相機(jī)與錄音,去河邊找鬼稠通。 笑死衬衬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的改橘。 我是一名探鬼主播滋尉,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼飞主!你這毒婦竟也來(lái)了狮惜?” 一聲冷哼從身側(cè)響起高诺,我...
    開(kāi)封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎碾篡,沒(méi)想到半個(gè)月后虱而,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡开泽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年牡拇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片穆律。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡惠呼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出峦耘,到底是詐尸還是另有隱情剔蹋,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布辅髓,位于F島的核電站泣崩,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏洛口。R本人自食惡果不足惜律想,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绍弟。 院中可真熱鬧技即,春花似錦、人聲如沸樟遣。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)豹悬。三九已至葵陵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間瞻佛,已是汗流浹背脱篙。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留伤柄,地道東北人绊困。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像适刀,于是被迫代替她去往敵國(guó)和親秤朗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容