Express+Jquery实现购物车的前后端

需求分析:

列表页list.html

html结构

 <p class="login-txt">登录</p>
    <p> <a href="register.html">注册</a></p>
    <p><a href="./shopCart.html">购物车</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>
列表页功能一: 初始化展示商品列表

前端代码

let page = 1;  //页码
let mask = document.querySelector(".mask") //获取dom

// 渲染数据
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}">加入购物车</div>
                </a>
            </li>
            `
        })
        $("#box ul").append(html)
    }
}
// 初始化加载数据
function initData() {
    axios.get("/product",{
        params: {
            page
        }
    })
    .then((res) => {
        render(res.data)
    })
}

initData()

后端代码

// 查询所有商品(分页显示)
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('查询数据库失败');
        } else {
            let data;
            if (result.length) {
                data = {
                    code: 0,
                    list: result
                }
            } else {
                data = {
                    code: 1,
                    msg: '没有结果 '
                }
            }
            res.send(data)
        }
    })
})
列表页功能二: 登录入口,可在本页面显示登录窗口,实现登录功能
// 每个页面中的登录
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")

    //绑定事件,单击登录时,显示弹窗
    loginTxt.onclick = function () {
        mask.classList.add("active")
    }

    //单击遮罩层,让遮罩层消失
    mask.onclick = function () {
        this.classList.remove("active")
    }

    //阻止冒泡
    login.onclick = function (e) {
        e.stopPropagation()
    }
}
login()
loginBox()
列表页功能三: 每个商品实现加入购物车功能

先验证是否登录,如何没有登录,进行登录,如果已登录,则把商品id和用户id传向后端接口

前端代码

function cart() {
    // 加入购物车
    function addCart() {
        $("#box ul").on("click", ".add_btn", function () {
            //验证用户是否登录
            let userId = $.cookie("user");
            let proId = $(this).data("id")  //获取商品Id
            console.log(proId);
            if (!userId) {
                //当cookie不存在,即没有登录
                mask.classList.add("active")
                return;
            }
            let data = {
                userId,
                proId
            }
            axios.post("/cart",data)
            .then((res)=>{
                console.log(res.data);
            })
        })

    }
    addCart();
}
cart()

后端代码

// 添加商品到购物车
router.post("/cart", (req, res) => {
    //接收参数
    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('数据库访问失败');
        } else {

            let data;
            if (result.length) {
                console.log('11');
                //当前用户存在该商品
                let cartId = result[0].cartId
                let num = result[0].num + 1
                // 更新商品数量 
                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: '添加购物车成功,数量更改'
                        })
                    }
                })
            } else {
                console.log(22);
                //当前用户不存在该商品
                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: '添加购物车成功,数量初始为1'
                        })
                    }
                })
            }
        }
    })
})
列表页功能四: 加入购物车

后端接口接收商品id和用户id,先验证该用户的当前商品是否存在,如果不存在,则新增,如果存在,则修改数量

前端代码

function cart() {
    // 加入购物车
    function addCart() {
        $("#box ul").on("click", ".add_btn", function () {
            //验证用户是否登录
            let userId = $.cookie("user");
            let proId = $(this).data("id")  //获取商品Id
            console.log(proId);
            if (!userId) {
                //当cookie不存在,即没有登录
                mask.classList.add("active")
                return;
            }
            let data = {
                userId,
                proId
            }
            axios.post("/cart",data)
            .then((res)=>{
                console.log(res.data);
            })
        })

    }
    addCart();
}
cart()

后端代码

// 添加商品到购物车
router.post("/cart", (req, res) => {
    //接收参数
    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('数据库访问失败');
        } else {

            let data;
            if (result.length) {
                console.log('11');
                //当前用户存在该商品
                let cartId = result[0].cartId
                let num = result[0].num + 1
                // 更新商品数量 
                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: '添加购物车成功,数量更改'
                        })
                    }
                })
            } else {
                console.log(22);
                //当前用户不存在该商品
                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: '添加购物车成功,数量初始为1'
                        })
                    }
                })
            }
        }
    })
})
列表页功能五: 跳转至详情页

单击商品,跳转到详情页,并传递当前商品id

前端代码

<a href="./detail.html?id=${item.Id}">商品</a>

详情页: detail.html

详情页功能一: 初始化获取商品id, 请求后端接口,获取商品信息并渲染

前端代码

// 获取Id
function getId(){
    let search = location.search; // "?id=100"
    let result = search.match(/^\?id=(\d+)$/)
    let id = result[1];
    return id
}
//渲染数据
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}">加入购物车</div>
            </a>
        </li>
        `
        $("#box ul").append(html)
    }
}
//获取指定id对应的商品信息
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('查询数据库失败');
        } else {
            let data;
            if (result.length) {
                data = {
                    code: 0,
                    list: result
                }
            } else {
                data = {
                    code: 1,
                    msg: '没有结果 '
                }
            }
            res.send(data)
        }
    })
})
详情页功能二: 加入购物车功能,逻辑参考列表页功能

购物车 shopCart.html

购物车功能一: 初始化请求后台接口,并传递当前用户id, 请求该用户的所有购物信息并展示

前端代码

// 查看用户是否登录
function checkIsLogin(userId) {
    if (!userId) return;
    //登录过
    $("h1").addClass("hide")
    $(".car").removeClass("hide")
}
//渲染数据
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)
    }
}
// 请求购物车列表数据
function loadData() {
    let userId = $.cookie("user")
    checkIsLogin(userId)
    // 请求数据
    axios.get("/cart", {
        params: {
            userId
        }
    })
        .then((res) => {
            render(res)
        })

}

后端代码

//查询购物车信息
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('查询数据库失败');
        } else {
            let data;
            if (result.length) {
                data = {
                    code: 0,
                    list: result
                }
            } else {
                data = {
                    code: 1,
                    msg: '没有结果 '
                }
            }
            res.send(data)
        }
    })
})

购物车功能二: 复选框全选的单击事件: 选中时,所有商品也要选中,取消选择时,所有商品也取消选择. 同时计算总价

计算总价

let total = 0;  //总价
//计算总价
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()
    })
}
购物车功能三. 每个商品复选框的单击事件: 单击时,要遍历所有商品的选中状态,都被选中,则选中“全选”复选框,都取消选中,则取消“全选”复选框。 同时计算总价

前端代码

//切换某一个商品的选择状态
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()
    })
}
购物车功能四. 加减数量: 获取原有数量,加或减后,调用后端接口,传递数量,CartId, 后端则把对应购物车信息的数量进行更新。 前端接收到更新成功后,计算小计价格,并同时计算总价

前端代码

//改变数量
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()
            })
    })
}

后端代码

//修改商品数量
router.put("/cart", (req, res) => {
    //接收参数
    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('数据库访问失败');
        } else {
            if (result.affectedRows === 1) {
                res.send({
                    code: 0,
                    msg: '添加购物车成功,数量更改'
                })
            }
        }
    })
})
购物车功能五: 删除: 调用后端接口,传递CartId, 在后端删除指定CartId的信息,前端接收到成功删除后,再次到后端请求当前用户所有购物车信息并渲染

前端代码

// 删除购物车信息
function delCart() {
    $(".list").on("click", ".ctrl a", function () {
        let cartId = $(this).data("id")
        axios.delete(`/cart/${cartId}`)
            .then((res) => {
                loadData()
            })
    })
}

后端代码

//删除购物车信息
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('查询数据库失败');
        } else {
            let data;
            if (result.affectedRows === 1) {
                data = {
                    code: 0,
                    msg: '删除成功'
                }
            }
            res.send(data)
        }
    })
})
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容