水果购物车案例

96 阅读4分钟

需求:

  1. 渲染功能
  2. 删除功能 filter过率
  3. 修改个数
  4. 全选反选
  5. 统计选中的总价和总数量 计算属性
  6. 持久化到本地

思路

渲染功能 image.png

修改了三步

 <style>
        * {
            margin: 0;
            padding: 0;
        }

        .banner-box {
            margin-top: 30px;
            margin-left: 400px;
        }

        .tr {
            margin-left: 400px;
            width: 500px;
            font-size: 20px;
            border-left: 15px;

        }

        .box1 {
            padding-right: 10px;
        }

        .td {
            float: left;
            width: 72px;
            height: 45px;
        }

        .tractive {
            background-color: antiquewhite;
        }
    </style>
    <div class="app-container" id="app">
        <!-- 顶部banner -->
        <div class="banner-box"><img
                src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F7252d6a8-c798-4582-a586-45d3a1b60855%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1708512060&t=8e627cb6e82387038e4a794c5dea2686"
                width="500px" height="300px"></div>
        <!-- 购物车主体 -->
        <div class="main" v-if="fruitList.length>0">
//此处为第一步,主体与空空如也的选择
            <div class="table">
                <!-- 头部 -->
                <div class="tr">
                    <th>
                    <td class="box1">选中</td>
                    <td class="box1">图片</td>
                    <td class="box1">单价</td>
                    <td class="box1">个数</td>
                    <td class="box1">小计</td>
                    <td class="box1">制作</td>
                    </th>


                </div>
            </div>
            <!-- 身体 -->
            <div class="tbody">
                <div v-for="(item,index) in fruitList" :key="item.id" class="tr" :class="{active:item.isChecked}">
 //此处为第二步背景颜色和选中的统一
 //v-for进行渲染将列表中的元素呈现
                    <div class="td"><input type="checkbox" v-model="item.isChecked"></div>
                    <div class="td"><img :src="item.icon" width="30px" height="30px"></div>
                    <div class="td">{{item.price}}</div>
                    <div class="td">
                        <div class="my-input-number">
                            <button class="decrease" @click="item.num--">-</button>
                            <span class="my-input__inner">{{item.num}}</span>
                            <button class="increase" @click="item.num++">+</button>
                        </div>
                    </div>
                    <div class="td">{{item.num*item.price}}</div>
                    <div class="td"><button>删除</button></div>


                </div>

            </div>
        </div>
        <!-- 底部 -->
        <div class="bottom">

        </div>
    </div>
    <div class="empty" v-else> 空空如也</div>
    <script src="./vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                //水果列表
                fruitList: [
                    {
                        id: 1,
                        icon: './img/草莓.png',
                        isChecked: true,
                        num: 2,
                        price: 6,
                    },
                    {
                        id: 2,
                        icon: './img/香蕉.png',
                        isChecked: false,
                        num: 7,
                        price: 20,
                    },
                    {
                        id: 3,
                        icon: './img/樱桃.png',
                        isChecked: true,
                        num: 2,
                        price: 6,
                    }
                ]

            }
        })
    </script>

删除

    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .banner-box {
            margin-top: 30px;
            margin-left: 400px;
        }

        .tr {
            margin-left: 400px;
            width: 500px;
            font-size: 20px;
            border-left: 15px;

        }

        .box1 {
            padding-right: 10px;
        }

        .td {
            float: left;
            width: 72px;
            height: 45px;
        }

        .tractive {
            background-color: antiquewhite;
        }
    </style>
    <div class="app-container" id="app">
        <!-- 顶部banner -->
        <div class="banner-box"><img
                src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F7252d6a8-c798-4582-a586-45d3a1b60855%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1708512060&t=8e627cb6e82387038e4a794c5dea2686"
                width="500px" height="300px"></div>
        <!-- 购物车主体 -->
        <div class="main" v-if="fruitList.length>0">
            <div class="table">
                <!-- 头部 -->
                <div class="tr">
                    <th>
                    <td class="box1">选中</td>
                    <td class="box1">图片</td>
                    <td class="box1">单价</td>
                    <td class="box1">个数</td>
                    <td class="box1">小计</td>
                    <td class="box1">制作</td>
                    </th>


                </div>
            </div>
            <!-- 身体 -->
            <div class="tbody">
                <div v-for="(item,index) in fruitList" :key="item.id" class="tr" :class="{active:item.isChecked}">
                    <div class="td"><input type="checkbox" v-model="item.isChecked"></div>
                    <div class="td"><img :src="item.icon" width="30px" height="30px"></div>
                    <div class="td">{{item.price}}</div>
                    <div class="td">
                        <div class="my-input-number">
                            <button :disabled="item.num==1" class="decrease" @click="item.num--">-</button>
                            <span class="my-input__inner">{{item.num}}</span>
                            <button class="increase" @click="item.num++">+</button>
//添加点击时数字加减,并且当减到1时,减禁用
                        </div>
                    </div>
                    <div class="td">{{item.num*item.price}}</div>
                    <div class="td"><button @click="del(item.id)">删除</button></div>
//给删除附上函数利用filter


                </div>

            </div>
        </div>
        <!-- 底部 -->
        <div class="bottom">

        </div>
    </div>
    <div class="empty" v-else> 空空如也</div>
    <script src="./vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                //水果列表
                fruitList: [
                    {
                        id: 1,
                        icon: './img/草莓.png',
                        isChecked: true,
                        num: 2,
                        price: 6,
                    },
                    {
                        id: 2,
                        icon: './img/香蕉.png',
                        isChecked: false,
                        num: 7,
                        price: 20,
                    },
                    {
                        id: 3,
                        icon: './img/樱桃.png',
                        isChecked: true,
                        num: 2,
                        price: 6,
                    }
                ]

            },
            methods:{
                del(id){
                    this.fruitList=this.fruitList.filter(item=>item.id!==id)
                }
            }
        })
    </script>

全选反选

    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .banner-box {
            margin-top: 30px;
            margin-left: 400px;
        }

        .tr {
            margin-left: 400px;
            width: 500px;
            font-size: 20px;
            border-left: 15px;

        }

        .box1 {
            padding-right: 10px;
        }

        .td {
            float: left;
            width: 72px;
            height: 45px;
        }

        .tractive {
            background-color: antiquewhite;
        }
        .bottom{
            float: left;
            width: 500px;
            margin-left: 400px;
        }
    </style>
    <div class="app-container" id="app">
        <!-- 顶部banner -->
        <div class="banner-box"><img
                src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F7252d6a8-c798-4582-a586-45d3a1b60855%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1708512060&t=8e627cb6e82387038e4a794c5dea2686"
                width="500px" height="300px"></div>
        <!-- 购物车主体 -->
        <div class="main" v-if="fruitList.length>0">
            <div class="table">
                <!-- 头部 -->
                <div class="tr">
                    <th>
                    <td class="box1">选中</td>
                    <td class="box1">图片</td>
                    <td class="box1">单价</td>
                    <td class="box1">个数</td>
                    <td class="box1">小计</td>
                    <td class="box1">制作</td>
                    </th>


                </div>
            </div>
            <!-- 身体 -->
            <div class="tbody">
                <div v-for="(item,index) in fruitList" :key="item.id" class="tr" :class="{active:item.isChecked}">
                    <div class="td"><input type="checkbox" v-model="item.isChecked"></div>
                    <div class="td"><img :src="item.icon" width="30px" height="30px"></div>
                    <div class="td">{{item.price}}</div>
                    <div class="td">
                        <div class="my-input-number">
                            <button :disabled="item.num==1" class="decrease" @click="item.num--">-</button>
                            <span class="my-input__inner">{{item.num}}</span>
                            <button class="increase" @click="item.num++">+</button>
                        </div>
                    </div>
                    <div class="td">{{item.num*item.price}}</div>
                    <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;</span>
                <!-- 结算按钮 -->
                <button class="pay">结算(6)</button>
            
            </div>
        </div>
    </div>
    <div class="empty" v-else> 空空如也</div>
    <script src="./vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                //水果列表
                fruitList: [
                    {
                        id: 1,
                        icon: './img/草莓.png',
                        isChecked: true,
                        num: 2,
                        price: 6,
                    },
                    {
                        id: 2,
                        icon: './img/香蕉.png',
                        isChecked: false,
                        num: 7,
                        price: 20,
                    },
                    {
                        id: 3,
                        icon: './img/樱桃.png',
                        isChecked: true,
                        num: 2,
                        price: 6,
                    }
                ]

            },
            computed:{
                //默认计算属性只能获取不能设置,要设置得完整写法

                // isAll(){
                //     return this.fruitList.every(item=>item.isChecked)
                // }
                //完整写法=get+set
                isAll:{
                    get(){
                        return this.fruitList.every(item=>item.isChecked)

                    },
                    set(value){
                        //基于拿到的布尔值,要让所有的小选框 同步状态
                        this.fruitList.forEach(item =>item.isChecked= value)
    //get使上面的小选框控制全选,set使全选控制小选框
                    }
                }

            },
            methods:{
                del(id){
                    this.fruitList=this.fruitList.filter(item=>item.id!==id)
                }
            }
        })
    </script>

统计选中的总价和总数量 计算属性

持久化到本地

    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .banner-box {
            margin-top: 30px;
            margin-left: 400px;
        }

        .tr {
            margin-left: 400px;
            width: 500px;
            font-size: 20px;
            border-left: 15px;

        }

        .box1 {
            padding-right: 10px;
        }

        .td {
            float: left;
            width: 72px;
            height: 45px;
        }

        .tractive {
            background-color: antiquewhite;
        }
        .bottom{
            float: left;
            width: 500px;
            margin-left: 400px;
        }
    </style>
    <div class="app-container" id="app">
        <!-- 顶部banner -->
        <div class="banner-box"><img
                src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F7252d6a8-c798-4582-a586-45d3a1b60855%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1708512060&t=8e627cb6e82387038e4a794c5dea2686"
                width="500px" height="300px"></div>
        <!-- 购物车主体 -->
        <div class="main" v-if="fruitList.length>0">
            <div class="table">
                <!-- 头部 -->
                <div class="tr">
                    <th>
                    <td class="box1">选中</td>
                    <td class="box1">图片</td>
                    <td class="box1">单价</td>
                    <td class="box1">个数</td>
                    <td class="box1">小计</td>
                    <td class="box1">制作</td>
                    </th>


                </div>
            </div>
            <!-- 身体 -->
            <div class="tbody">
                <div v-for="(item,index) in fruitList" :key="item.id" class="tr" :class="{active:item.isChecked}">
                    <div class="td"><input type="checkbox" v-model="item.isChecked"></div>
                    <div class="td"><img :src="item.icon" width="30px" height="30px"></div>
                    <div class="td">{{item.price}}</div>
                    <div class="td">
                        <div class="my-input-number">
                            <button :disabled="item.num==1" class="decrease" @click="item.num--">-</button>
                            <span class="my-input__inner">{{item.num}}</span>
                            <button class="increase" @click="item.num++">+</button>
                        </div>
                    </div>
                    <div class="td">{{item.num*item.price}}</div>
                    <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">总价{{totalPrice}}&nbsp;&nbsp;&nbsp;&nbsp;</span>
                <!-- 结算按钮 -->
                <button class="pay">结算({{totalCount}})</button>
            
            </div>
        </div>
    </div>
    <div class="empty" v-else> 空空如也</div>
    <script src="./vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                //水果列表
                fruitList: [
                    {
                        id: 1,
                        icon: './img/草莓.png',
                        isChecked: true,
                        num: 2,
                        price: 6,
                    },
                    {
                        id: 2,
                        icon: './img/香蕉.png',
                        isChecked: false,
                        num: 7,
                        price: 20,
                    },
                    {
                        id: 3,
                        icon: './img/樱桃.png',
                        isChecked: true,
                        num: 2,
                        price: 6,
                    }
                ]

            },
            computed:{
                //默认计算属性只能获取不能设置,要设置得完整写法

                // isAll(){
                //     return this.fruitList.every(item=>item.isChecked)
                // }
                //完整写法=get+set
                isAll:{
                    get(){
                        return this.fruitList.every(item=>item.isChecked)

                    },
                    set(value){
                        //基于拿到的布尔值,要让所有的小选框 同步状态
                        this.fruitList.forEach(item =>item.isChecked= value)
                        
                    }
                },
//统计选中的总数 reduce                
                totalCount(){
            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)

                }

            },
            methods:{
                del(id){
                    this.fruitList=this.fruitList.filter(item=>item.id!==id)
                }
            },
            watch:{
                deep:true,
                hander(newValue){
                    //需要将变化后的newValue存入本地(转JSON)
                    localStorage.setItem('list',JSON.stringify(newValue))
                }
            }
        })
    </script>

</body>