Vue案例:商品购物车(三)

效果图

底部合计

合计就是把选中商品的金额全部加到一起,当然它也不止这点功能,它还可以看你选了几件商品,还有批量删除功能,最左边还有一个跟顶部一样的全选框。

批量删除功能:

        allDel() {
            this.Commodity =
                this.Commodity.filter(item => {
                    // console.log(item)
                    return item.decide === false
                });
        },

选中的商品:

settle() {
            let a = 0
            this.Commodity.forEach(item => {
                if (item.decide === true) {
                    a++
                }
            })
            return a
        }
合计

这个底部合计虽然是在底部的,但是在商品列表很长的时候,它其实是会出现在屏幕的最下方的,等到,用户到达最下方的时候会重新回归原位。

scrollToTop() {
            // 获取视窗高度
            let domHight = document.body.offsetHeight;
            // dom滚动位置
            let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
            //   获取窗口高度
            let height = document.documentElement.clientHeight + 100
            // 元素的高度
            // let summarize = this.$refs.summarize.scrollTop
            if (domHight <= 600) {
                return
            }
            if (domHight  < scrollTop + height) {
                this.fixed = false
            } else {
                this.fixed = true
            }
        }
    },
    mounted() {
        window.addEventListener('scroll', this.scrollToTop);
    },
    destroyed() {
        // 跳页的时候销毁
        window.removeEventListener('scroll', '')
    },

好了,差不多这个案例的功能,和实现原理就讲完了,下面有这个案例的全部代码,如果有什么不好的地方,大家可以批评。

这是全部代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>商品购物车</title>
    <link rel="stylesheet" href="./css/index.css">
</head>

<body>
    <div id="app">
        <div class="big-box">
            <div class="title-box" ref="title">
                <div class="checktext">
                    <i :class='{allCheck:all,checkbox:true}' @click='allCheck'></i>
                    <span>全选</span>
                </div>
                <div class="text-box">
                    <span>单价</span>
                    <span>数量</span>
                    <span>小计(元)</span>
                    <span @click='last'>{{del?'完成':'编辑'}}</span>
                </div>
            </div>
            <ul class="content-box">
                <li v-for='(item,index) in Commodity'>
                    <div class="img-box">
                        <div class="img-check">
                            <i :class='{allCheck:item.decide,checkbox:true}' @click='decideCheck(index)'></i>
                            <img :src="item.src" alt="">
                        </div>
                        <div class="introduce">
                            <p>{{item.name}}</p>
                            <p>{{item.text}}</p>
                        </div>
                    </div>
                    <div class="money">
                        <div>¥<strong>{{item.money.toFixed(2)}}</strong></div>
                        <div class="quantity-box">
                            <div class="quantity">
                                <span @click='minus(index)'
                                    :style="{'cursor':item.quantity<=1?'no-drop':'pointer'}">-</span>
                                <input type="number" @blur='lose' v-model='item.quantity'>
                                <span @click='add(index)'
                                    :style="{'cursor':item.quantity>=50?'no-drop':'pointer'}">+</span>
                            </div>
                            <p>最多能只能买50件</p>
                        </div>
                        <div style="color: red;">¥<strong>{{item.subtotal.toFixed(2)}}</strong></div>
                        <div class="del-box">
                            <p :style="{'display':del? 'none':'block'}">--</p>
                            <i :style="{'display':del?'inline-block':'none'}" class="del" @click='deleteLi(index)'></i>
                        </div>
                    </div>
                </li>
            </ul>
            <div class="summarize-box">
                <div :class='{summarize:true,summarizeFixed:fixed}' ref="summarize">
                    <div class="summarizeLeft">
                        <div class="summarizeCheck">
                            <i :class='{allCheck:all,checkbox:true}' @click='allCheck'></i>
                            <span>全选</span>
                        </div>
                        <p @click='allDel'>删除选中的商品</p>
                        <p>一共有{{summarize}}件商品,已经选了<strong style="color: #47e3ee;">{{settle}}</strong>件</p>
                    </div>
                    <div class="summarizeRight">
                        <p>合计(不包运费):<strong>¥{{allMoney.toFixed(2)}}</strong></p>
                        <button>购买</button>
                    </div>
                </div>
            </div>
            
        </div>
    </div>
    <script src="../../js/vue.js"></script>
    <script src="./js/index.js"></script>
</body>

</html>
body {
    margin: 0;
    padding: 0;
}

span,
p,
input,
i,
ul,
li,
input,
button,
strong {
    margin: 0;
    padding: 0;
    list-style: none;
}

.big-box {
    width: 100%;
    height: auto;
    margin: 0 auto;
    background-color: #edfcfd;
    box-shadow: 0 1px 6px #999;
    overflow: hidden;
}

.title-box {
    width: 100%;
    height: 48px;
    background-color: #f5f5f5;
    box-shadow: 0 1px 1px #d1d1d1;
    display: flex;
    justify-content: space-evenly;
    align-items: center;
    padding: 0 10px;
    margin: 0 auto;
}

.title-box div {
    height: 100%;
    line-height: 48px;
    color: #999;
}

/* 全选 */
.checktext {
    width: 40%;
    display: flex;
    align-items: center;
}

.checktext span {
    font-size: 18px;
    color: #333;
}

/* 介绍 */
.text-box {
    width: 60%;
    text-align: center;
    overflow: hidden;
}

.text-box span {
    float: left;
    width: 25%;
    height: 100%;
    font-weight: 300;
}

.text-box span:last-child {
    color: #47e3ee;
    cursor: pointer;
}

.checkbox {
    display: block;
    width: 18px;
    height: 18px;
    margin-right: 5px;
    border: 1px solid #777;
    cursor: pointer;
}

.allCheck {
    background: url('../images/yes.png') no-repeat;
    background-size: 18px;
    background-color: #47e3ee;
}

/* 商品区 */
.content-box {
    height: auto;
    width: 100%;
    background-color: #edfcfd;
}

.content-box li {
    height: 180px;
    width: 100%;
    box-shadow: 0 1px 3px #d1d1d1;
    margin: 4px 0;
    background-color: white;
}

.img-box {
    float: left;
    width: 40%;
    height: 100%;
}

.img-check {
    float: left;
    width: 50%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: space-around;
    overflow: hidden;
}

.img-check img {
    max-width: 140px;
    min-height: 120px;
}

.introduce {
    float: left;
    width: 50%;
    height: 100%;
    overflow: hidden;
}

.introduce p {
    color: #333;
    font-size: 18px;
    width: 100%;
    height: auto;
    margin-top: 40px;
    margin-left: 10px;
    word-wrap: break-word;
    word-break: normal;
}

.introduce p:nth-child(2) {
    margin-top: 0;
    font-size: 16px;
    color: #999;
    font-weight: 300;
}

.money {
    float: left;
    width: 60%;
    height: 100%;
    line-height: 180px;
}

.money div {
    float: left;
    width: 25%;
    height: 100%;
    text-align: center;
    font-size: 20px;
    color: #333;
}

.quantity-box {
    display: flex;
    flex-direction: column;
    justify-content: center;
    overflow: hidden;
}

.quantity-box .quantity {
    display: flex;
    justify-content: center;
    align-items: flex-end;
    width: 100%;
    height: 46px;
}

.quantity-box .quantity span {
    width: 24px;
    height: 26px;
    border: 1px solid #99999966;
    line-height: 26px;
    color: #777;
    user-select: none;
}

.quantity-box .quantity span:hover {
    color: #47e3ee;
}

.quantity input {
    width: 50px;
    height: 26px;
    outline: none;
    border: 0;
    border-top: 1px solid #99999966;
    border-bottom: 1px solid #99999966;
    text-align: center;
}

.quantity-box p {
    float: left;
    width: 100%;
    height: 20px;
    color: #999;
    font-size: 14px;
    line-height: 2;
}


.quantity input::-webkit-outer-spin-button,
.quantity input::-webkit-inner-spin-button {
    -webkit-appearance: none !important;
    margin: 0;
}

.money div .del {
    display: inline-block;
    width: 20px;
    height: 20px;
    background: url('../images/del.png') no-repeat;
    background-size: 20px;
    cursor: pointer;
}

.summarize-box {
    width: 100%;
    height: 120px; 
}

.summarize {
    width: 100%;
    height: 120px;
    margin: 20px 0;
    background-color: white;
    box-shadow: 0 1px 3px rgb(153, 153, 153);
    color: #999;
}

.summarizeFixed {
    position: fixed;
    bottom: 0;
    left: 0;
    margin: 0;
    height: 120px;
}

.summarize .summarizeLeft {
    float: left;
    width: 50%;
    height: 100%;
    line-height: 80px;
    display: flex;
    align-items: center;
}

.summarize .summarizeLeft p {
    margin-left: 20px;
    user-select: none;
}

.summarize .summarizeLeft p:first-of-type:hover {
    color: #47e3ee;
    cursor: pointer;
}

.summarizeLeft .summarizeCheck {
    width: auto;
    height: 100%;
    margin-left: 20px;
    display: flex;
    align-items: center;
}

.summarize .summarizeRight {
    float: left;
    width: 50%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}

.summarize .summarizeRight strong {
    font-size: 20px;
    color: red;
}

.summarize .summarizeRight button {
    width: 120px;
    height: 40px;
    background-color: #ff5f5f;
    color: white;
    border: 0;
    font-size: 16px;
    box-shadow: 0 1px 1px #999;
    margin-left: 20px;
    border-radius: 5px;
    cursor: pointer;
}
Vue.config.productionTip = false

new Vue({
    el: '#app',
    data: {
        Commodity: [{
            name: '相机',
            text: '一亿像素,画面更清晰',
            src: './images/camera.jpeg',
            // 数量
            quantity: 1,
            // 单价
            money: 99.10,
            // 小计
            subtotal: 0,
            decide: false
        }, {
            name: '毛绒衬衫',
            text: '最新推出,八折优惠',
            src: './images/clothes1.jpeg',
            quantity: 1,
            money: 128.88,
            subtotal: 0,
            decide: false
        }, {
            name: '保暖大衣',
            text: '冬季的必备物品',
            src: './images/clothes2.jpeg',
            quantity: 1,
            money: 246.9,
            subtotal: 0,
            decide: false
        }, {
            name: 'vivo X70 Pro',
            text: '最新推出的vivo手机',
            src: './images/mobile.jpg',
            quantity: 1,
            money: 3999,
            subtotal: 0,
            decide: false
        }, {
            name: '电动牙刷',
            text: '一次充电,超长续航',
            src: './images/toothbrush.jpg',
            quantity: 1,
            money: 399,
            subtotal: 0,
            decide: false
        }, {
            name: '儿童玩具一',
            text: '一个普普通通的玩具小船',
            src: './images/toy1.jpeg',
            quantity: 1,
            money: 60.99,
            subtotal: 0,
            decide: false
        }, {
            name: '儿童玩具二',
            text: '可爱的毛绒玩具',
            src: './images/toy2.jpeg',
            quantity: 1,
            money: 58,
            subtotal: 0,
            decide: false
        }, {
            name: '儿童玩具三',
            text: '趣味玩具',
            src: './images/toy3.jpeg',
            quantity: 1,
            money: 89,
            subtotal: 0,
            decide: false
        }],
        del: false,
        all: false,
        fixed: false
    },
    methods: {
        last(i) {
            this.del = !this.del
        },
        add(i) {
            if (this.Commodity[i].quantity >= 50) return
            this.Commodity[i].quantity++
        },
        minus(i) {
            if (this.Commodity[i].quantity <= 1) return
            this.Commodity[i].quantity--
        },
        lose(i) {
            if (this.Commodity[i].quantity > 50 || this.Commodity[i].quantity < 0 || this.Commodity[i].quantity === '') {
                alert('数量不正确')
                this.Commodity[i].quantity = 1
            }
        },
        deleteLi(i) {
            this.Commodity.splice(i, 1)
            this.decideCheck('')
        },
        allCheck() {
            this.all = !this.all
            this.Commodity.forEach(p => {
                p.decide = this.all
            })
        },
        decideCheck(i) {
            if (i !== '') {
                this.Commodity[i].decide = !this.Commodity[i].decide
            }
            for (let index = 0; index < this.Commodity.length; index++) {
                if (this.Commodity[index].decide === false) {
                    this.all = false
                    return
                }
            }
            this.all = true
        },
        allDel() {
            this.Commodity =
                this.Commodity.filter(item => {
                    // console.log(item)
                    return item.decide === false
                });
        },
        scrollToTop() {
            // 获取视窗高度
            let domHight = document.body.offsetHeight;
            // dom滚动位置
            let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
            //   获取窗口高度
            let height = document.documentElement.clientHeight + 100
            // 元素的高度
            // let summarize = this.$refs.summarize.scrollTop
            if (domHight <= 600) {
                return
            }
            if (domHight  < scrollTop + height) {
                this.fixed = false
            } else {
                this.fixed = true
            }
        }
    },
    mounted() {
        window.addEventListener('scroll', this.scrollToTop);
    },
    destroyed() {
        // 跳页的时候销毁
        window.removeEventListener('scroll', '')
    },
    computed: {
        summarize() {
            return this.Commodity.length
        },
        settle() {
            let a = 0
            this.Commodity.forEach(item => {
                if (item.decide === true) {
                    a++
                }
            })
            return a
        },
        allMoney() {
            let money = 0
            this.Commodity.forEach(item => {
                if (item.decide === true) {
                    money = money + item.subtotal
                }
            })
            return money
        }
    },
    watch: {
        Commodity: {
            handler(newvalue, oldvalue) {
                // console.log(newvalue)
                if (newvalue.length > 0) {
                    for (let index = 0; index < newvalue.length; index++) {
                        newvalue[index].subtotal = newvalue[index].quantity * newvalue[index].money
                    }
                }
            },
            deep: true,
            immediate: true
        }
    }
})

本文章由javascript技术分享原创和收集

发表评论 (审核通过后显示评论):