vue实现购物车功能

实现功能

CSS部分

   <style>
        .tr {
            display: flex;
        }

        .th {
            margin: 10px;
            width: 20%;
            height: 50%;
        }

        .td {
            display: flex;
            margin: 10px;
            width: 20%;
            height: 100px;
            align-items: center;
        }

        .app-container .banner-box {
            border-radius: 20px;
            overflow: hidden;
            margin-bottom: 10px;
        }

        .app-container .banner-box img {
            width: 100%;
        }

        .app-container .nav-box {
            background: #ddedec;
            height: 60px;
            border-radius: 10px;
            padding-left: 20px;
            display: flex;
            align-items: center;
        }

        .app-container .nav-box .my-nav {
            display: inline-block;
            background: #5fca71;
            border-radius: 5px;
            width: 90px;
            height: 35px;
            color: white;
            text-align: center;
            line-height: 35px;
            margin-right: 10px;
        }

        .breadcrumb {
            font-size: 16px;
            color: gray;
        }

        .table {
            width: 100%;
            text-align: left;
            border-radius: 2px 2px 0 0;
            border-collapse: separate;
            border-spacing: 0;
        }

        .table img {
            width: 100px;
            height: 100px;
        }

        button {
            outline: 0;
            box-shadow: none;
            color: #fff;
            background: #d9363e;
            border-color: #d9363e;
            color: #fff;
            background: #d9363e;
            border-color: #d9363e;
            line-height: 1.5715;
            position: relative;
            display: inline-block;
            font-weight: 400;
            white-space: nowrap;
            text-align: center;
            background-image: none;
            border: 1px solid transparent;
            box-shadow: 0 2px 0 rgb(0 0 0 / 2%);
            cursor: pointer;
            transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
            touch-action: manipulation;
            height: 32px;
            padding: 4px 15px;
            font-size: 14px;
            border-radius: 2px;
        }

        button.pay {
            background-color: #3f85ed;
            margin-left: 20px;
        }

        .bottom {
            height: 60px;
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding-right: 20px;
            border: 1px solid #f0f0f0;
            border-top: none;
            padding-left: 20px;
        }

        .right-box {
            display: flex;
            align-items: center;
        }

        .empty {
            text-align: center;
            font-size: 30px;
        }

        /* 选中时颜色是灰色 */
        .tr.active {
            background-color: #f5f7fa;
        }
    </style>

HTML

<body>
<div class="app-container" id="app">
    <!-- 顶部banner -->
    <div class="banner-box"><img src="./fruitPot/封面.png" alt=""/></div>
    <!-- 面包屑 -->
    <div class="breadcrumb">
        <span>🏠</span>
        <span>购物车</span>
    </div>
    <!-- 购物车主体 -->
    <div class="main" v-if="fruitlist.length>0">
        <div class="table">
            <!-- 头部 -->
            <div class="thead">
                <div class="tr">
                    <div class="th">选中</div>
                    <div class="th th-pic">图片</div>
                    <div class="th">单价</div>
                    <div class="th num-th">个数</div>
                    <div class="th">小计</div>
                    <div class="th">操作</div>
                </div>
            </div>
            <!-- 身体 -->
            <div class="tbody">
                <div class="tr" :class="{active:item.isChecked}" v-for="(item) in fruitlist" :key="item.id">
                    <div class="td"><input type="checkbox" v-model="item.isChecked"/></div>
                    <div class="td pot"><img :src="item.icon" alt=""/></div>
                    <div class="td">{{ item.price }}</div>
                    <div class="td">
                        <div class="my-input-number">
                            <!--disabled:禁用  -->
                            <button :disabled="item.num <=0 " class="decrease" @click="sub(item.id)"> -</button>
                            <span class="my-input__inner">{{ item.num }}</span>
                            <button class="increase" @click="add(item.id)"> +</button>
                        </div>
                    </div>
                    <div class="td">{{item.price * item.num}}</div>
                    <!-- 删除filter -->
                    <div class="td">
                        <button @click="del(item.id)">删除</button>
                    </div>
                </div>

            </div>
        </div>
        <!-- 底部 -->
        <div class="bottom">
            <!-- 全选 -->
            <label class="check-all">
                <input type="checkbox" v-model="isAll"/>全选
            </label>
            <div class="right-box">
                <!-- 所有商品总价 -->
                <span class="price-box">总价&nbsp;&nbsp;:&nbsp;&nbsp;¥&nbsp;
							<span class="price">{{totalPrice()}}</span>
						</span>
                <!-- 结算按钮 -->
                <button class="pay">结算( {{totalNum()}} )</button>
            </div>
        </div>
    </div>
    <!-- 空车 -->
    <div class="empty" v-else>🛒空空如也</div>
</div>

JS

<script>
    <!--    初始化-->
    // const defaultArr =[ ]
    const app = new Vue({
        el: '#app',
        data: {
            // // 水果列表从本地读取
            // // JSON.parse将本地JSON格式转回去
            // 加||defaultArr是怕用户删除完,下次刷新后只剩下空空如也
            // fruitlist: JSON.parse(localStorage.getItem('list'))||defaultArr,
            fruitlist: [{
                id: 1,
                icon: './fruitPot/苹果.png',
                isChecked: true,
                num: 2,
                price: 6,
            },
                {
                    id: 2,
                    icon: './fruitPot/苹果.png',
                    isChecked: false,
                    num: 7,
                    price: 20,
                },
                {
                    id: 3,
                    icon: './fruitPot/鸭梨.png',
                    isChecked: true,
                    num: 2,
                    price: 6,
                },
            ],

            },

        // 计算属性
        computed: {
            isAll:{
                // isAll:  对象
                // get()   方法
                get(){
                    // 必须所有的小选框都选中,全选按钮才选中--every
                    // 此时的item与上面的item没关联,只是一个形参
                    return this.fruitlist.every(item => {return  item.isChecked===true})
                },
                // value是复选框的布尔值
               set(value){
               //console.log(value)  ture/false
               //基于拿到的布尔值,要让所有的小选框同步状态
                   this.fruitlist.forEach(item =>item.isChecked = value)
               }

            }
        },
        methods: {
            del(id) {
                this.fruitlist = this.fruitlist.filter(item => item.id !== id)
            },
            add(id) {
                // 1.根据id 找到数组中的对应项 --find
                const fruit = this.fruitlist.find(item => item.id === id)
                // 2.操作num数量
                fruit.num++
            },
            sub(id) {
                const fruit = this.fruitlist.find(item => item.id === id)
                fruit.num--
            },
        //     总数量  reduce
            totalNum(){
                return this.fruitlist.reduce((sum, item) => {
                    if (item.isChecked) {
                        // 选中 → 需要累加
                        return sum + item.num
                    } else {
                        // 没选中 → 不需要累加
                        return sum
                    }
                }, 0)
            },
            // 总价
            totalPrice(){
                return this.fruitlist.reduce((sum, item) => {
                    if (item.isChecked) {
                        return sum + item.num * item.price
                    } else {
                        return sum
                    }
                }, 0)
            },
        },
    //     监视数据变化
        watch:{
            fruitlist:{
                deep:true,
                handler(newValue){
                    console.log(newValue)
                //     需要将变化后的newValue存入本地(转JSON)
                    localStorage.setItem('list',JSON.stringify(newValue))
                }
            }
        }
    })
</script>

全部代码

<!-- 标签\watch\methods -->
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>水果购物车</title>
    <style>
        .tr {
            display: flex;
        }

        .th {
            margin: 10px;
            width: 20%;
            height: 50%;
        }

        .td {
            display: flex;
            margin: 10px;
            width: 20%;
            height: 100px;
            align-items: center;
        }

        .app-container .banner-box {
            border-radius: 20px;
            overflow: hidden;
            margin-bottom: 10px;
        }

        .app-container .banner-box img {
            width: 100%;
        }

        .app-container .nav-box {
            background: #ddedec;
            height: 60px;
            border-radius: 10px;
            padding-left: 20px;
            display: flex;
            align-items: center;
        }

        .app-container .nav-box .my-nav {
            display: inline-block;
            background: #5fca71;
            border-radius: 5px;
            width: 90px;
            height: 35px;
            color: white;
            text-align: center;
            line-height: 35px;
            margin-right: 10px;
        }

        .breadcrumb {
            font-size: 16px;
            color: gray;
        }

        .table {
            width: 100%;
            text-align: left;
            border-radius: 2px 2px 0 0;
            border-collapse: separate;
            border-spacing: 0;
        }

        .table img {
            width: 100px;
            height: 100px;
        }

        button {
            outline: 0;
            box-shadow: none;
            color: #fff;
            background: #d9363e;
            border-color: #d9363e;
            color: #fff;
            background: #d9363e;
            border-color: #d9363e;
            line-height: 1.5715;
            position: relative;
            display: inline-block;
            font-weight: 400;
            white-space: nowrap;
            text-align: center;
            background-image: none;
            border: 1px solid transparent;
            box-shadow: 0 2px 0 rgb(0 0 0 / 2%);
            cursor: pointer;
            transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
            touch-action: manipulation;
            height: 32px;
            padding: 4px 15px;
            font-size: 14px;
            border-radius: 2px;
        }

        button.pay {
            background-color: #3f85ed;
            margin-left: 20px;
        }

        .bottom {
            height: 60px;
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding-right: 20px;
            border: 1px solid #f0f0f0;
            border-top: none;
            padding-left: 20px;
        }

        .right-box {
            display: flex;
            align-items: center;
        }

        .empty {
            text-align: center;
            font-size: 30px;
        }

        /* 选中时颜色是灰色 */
        .tr.active {
            background-color: #f5f7fa;
        }
    </style>
</head>
<body>
<div class="app-container" id="app">
    <!-- 顶部banner -->
    <div class="banner-box"><img src="./fruitPot/封面.png" alt=""/></div>
    <!-- 面包屑 -->
    <div class="breadcrumb">
        <span>🏠</span>
        <span>购物车</span>
    </div>
    <!-- 购物车主体 -->
    <div class="main" v-if="fruitlist.length>0">
        <div class="table">
            <!-- 头部 -->
            <div class="thead">
                <div class="tr">
                    <div class="th">选中</div>
                    <div class="th th-pic">图片</div>
                    <div class="th">单价</div>
                    <div class="th num-th">个数</div>
                    <div class="th">小计</div>
                    <div class="th">操作</div>
                </div>
            </div>
            <!-- 身体 -->
            <div class="tbody">
                <div class="tr" :class="{active:item.isChecked}" v-for="(item) in fruitlist" :key="item.id">
                    <div class="td"><input type="checkbox" v-model="item.isChecked"/></div>
                    <div class="td pot"><img :src="item.icon" alt=""/></div>
                    <div class="td">{{ item.price }}</div>
                    <div class="td">
                        <div class="my-input-number">
                            <!--disabled:禁用  -->
                            <button :disabled="item.num <=0 " class="decrease" @click="sub(item.id)"> -</button>
                            <span class="my-input__inner">{{ item.num }}</span>
                            <button class="increase" @click="add(item.id)"> +</button>
                        </div>
                    </div>
                    <div class="td">{{item.price * item.num}}</div>
                    <!-- 删除filter -->
                    <div class="td">
                        <button @click="del(item.id)">删除</button>
                    </div>
                </div>

            </div>
        </div>
        <!-- 底部 -->
        <div class="bottom">
            <!-- 全选 -->
            <label class="check-all">
                <input type="checkbox" v-model="isAll"/>全选
            </label>
            <div class="right-box">
                <!-- 所有商品总价 -->
                <span class="price-box">总价&nbsp;&nbsp;:&nbsp;&nbsp;¥&nbsp;
							<span class="price">{{totalPrice()}}</span>
						</span>
                <!-- 结算按钮 -->
                <button class="pay">结算( {{totalNum()}} )</button>
            </div>
        </div>
    </div>
    <!-- 空车 -->
    <div class="empty" v-else>🛒空空如也</div>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>

<script>
    <!--    初始化-->
    // const defaultArr =[ ]
    const app = new Vue({
        el: '#app',
        data: {
            // // 水果列表从本地读取
            // // JSON.parse将本地JSON格式转回去
            // 加||defaultArr是怕用户删除完,下次刷新后只剩下空空如也
            // fruitlist: JSON.parse(localStorage.getItem('list'))||defaultArr,
            fruitlist: [{
                id: 1,
                icon: './fruitPot/苹果.png',
                isChecked: true,
                num: 2,
                price: 6,
            },
                {
                    id: 2,
                    icon: './fruitPot/苹果.png',
                    isChecked: false,
                    num: 7,
                    price: 20,
                },
                {
                    id: 3,
                    icon: './fruitPot/鸭梨.png',
                    isChecked: true,
                    num: 2,
                    price: 6,
                },
            ],

            },

        // 计算属性
        computed: {
            isAll:{
                // isAll:  对象
                // get()   方法
                get(){
                    // 必须所有的小选框都选中,全选按钮才选中--every
                    // 此时的item与上面的item没关联,只是一个形参
                    return this.fruitlist.every(item => {return  item.isChecked===true})
                },
                // value是复选框的布尔值
               set(value){
               //console.log(value)  ture/false
               //基于拿到的布尔值,要让所有的小选框同步状态
                   this.fruitlist.forEach(item =>item.isChecked = value)
               }

            }
        },
        methods: {
            del(id) {
                this.fruitlist = this.fruitlist.filter(item => item.id !== id)
            },
            add(id) {
                // 1.根据id 找到数组中的对应项 --find
                const fruit = this.fruitlist.find(item => item.id === id)
                // 2.操作num数量
                fruit.num++
            },
            sub(id) {
                const fruit = this.fruitlist.find(item => item.id === id)
                fruit.num--
            },
        //     总数量  reduce
            totalNum(){
                return this.fruitlist.reduce((sum, item) => {
                    if (item.isChecked) {
                        // 选中 → 需要累加
                        return sum + item.num
                    } else {
                        // 没选中 → 不需要累加
                        return sum
                    }
                }, 0)
            },
            // 总价
            totalPrice(){
                return this.fruitlist.reduce((sum, item) => {
                    if (item.isChecked) {
                        return sum + item.num * item.price
                    } else {
                        return sum
                    }
                }, 0)
            },
        },
    //     监视数据变化
        watch:{
            fruitlist:{
                deep:true,
                handler(newValue){
                    console.log(newValue)
                //     需要将变化后的newValue存入本地(转JSON)
                    localStorage.setItem('list',JSON.stringify(newValue))
                }
            }
        }
    })
</script>
</body>
</html>

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现购物车功能需要结合Spring Boot和Vue框架,以下是一种可能的实现方案。 首先,在Spring Boot中创建商品和购物车相关的数据模型和数据库表结构。可以创建商品表、购物车表,以及中间表来建立商品和购物车之间的关系。通过JPA或者MyBatis等框架与数据库进行交互,实现增删改查等基本的数据操作。 接下来,使用Spring Boot创建商品和购物车相关的接口。可以创建商品的添加、删除、修改等接口,以及购物车的商品添加、删除、修改接口。在接口中,可以处理一些逻辑,比如商品添加到购物车时可以判断购物车是否已存在该商品,如果存在则数量增加,不存在则添加新的购物车项。 在Vue中,创建商品列表和购物车页面。可以使用axios等工具从后端获取商品列表,并展示给用户。用户在页面上可以点击“加入购物车”按钮,将选中的商品添加到购物车中。在购物车页面,展示当前用户已添加的购物车商品列表,并实现数量增减和删除的功能。每次数量改变或删除操作时,通过接口与后端进行数据交互,更新购物车中的商品信息。 在Vue中,还需要实现购物车商品总价的计算和结算功能。可以通过遍历购物车商品列表,计算每个商品的小计,再将所有小计相加得到总价。用户点击结算按钮时,可以将购物车商品列表传递给后端进行支付操作。 以上是基本的购物车功能实现方案。当然,具体实现过程中可能还会涉及到其他细节问题,比如商品详情展示、用户登录、权限控制等,需要根据实际需求进一步完善和实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值