第11课:开发进行时之购物车

第11课:开发进行时之购物车

对于一个电商类网站而言,购物车是一个实用性很强的功能。很多用户更多的时候更愿意将心仪但是不会立即购买的产品放进购物车而不是放入收藏夹。所以购物车不仅仅是用来结算用户购买的产品,很多时候也起到一个收藏的作用。我们在设计购物车的时候需要根据平台性质的不同进行不同的设计。

本文将带领大家完成一个购物车。

无论你是什么平台,购物车都会具有以下几个核心功能。

  • 商品基本信息展示
  • 商品数量编辑
  • 商品价格的实时计算
  • 结账商品的选则

我们要完成的购物车模仿淘宝的购物车页面来完成,如下图所示。

本文主要讲述的内容是购物车,所以移除了收藏夹相关内容。

首先,我们对页面结构进行拆分。头部有一个全选按钮。在列表中,第一级是店铺,店铺的下一级才是商品,通过店铺前面的选择框可以全选购物车中该店铺的商品。在商品那一级中有商品选择框和一些商品基本信息,以及对商品数量的编辑功能,或者对商品进行删除。最末尾有全选按钮、删除按钮,所选商品种类的统计,商品价格的实时计算。

按照惯例首先来确定该页面数据,如下所示。

data: {
    shopCarData: {
         listData: [//购物车列表数据
            {
                shopId: '1',//店铺ID
                shopName: 'rhodon旗舰店',//店铺名称
                shopSelect:false,
                goodsList: [//商品列表
                    {
                         id: '12',//商品ID
                         img: 'https://img.alicdn.com/bao/uploaded/i4/TB1KLz.NVXXXXcpXXXXXXXXXXXX_!!0-item_pic.jpg_80x80.jpg',//商品图片
                         title: 'RHODON月光石麋鹿项链女吊坠925纯银简约鹿角锁骨链银饰品银',//商品名称
                         sizeAndColor: '颜色分类:月光石麋鹿项链(联系客服发顺丰)',//规格和颜色的描述
                         price: 398.00,//商品单价
                         number: 1,//所选商品数量
                         total: '499',//商品库存
                         amount: '',//商品总价
                         isSelect:false
                    },
                    {
                         id: '13',//商品ID
                         img: 'https://img.alicdn.com/imgextra/i8/TB1iXwrRFXXXXa9XpXXYXGcGpXX_M2.SS2_430x430q90.jpg',//商品图片
                         title: 'RHODON圣诞麋鹿镀14K金925银项链女士鹿角日韩纯银吊坠简约锁骨链',//商品名称
                         sizeAndColor: '颜色分类:圣诞麋鹿项链(联系客服发顺丰)',//规格和颜色的描述
                         price: 298.00,//商品单价
                         number: 1,//所选商品数量
                         total: '499',//商品库存
                         amount: '',//商品总价
                         isSelect:false
                    }
                ]
            },
           ……
        ],
        carData: {
             number: '',//选中商品的种类
             price: ''//所选商品金额合计
         }
    }
},

有了数据,再结合我们的 HTML 代码与 CSS 样式,购物车模块的页面就可以呈现在用户面前。

HTML 结构如下。

<section class="shop_car_box">
    <div class="shop_car_head">
        <div class="head_choose_all">全选</div>
        <div class="head_info">商品信息</div>
        <div class="head_number"></div>
        <div class="head_choose_price">单价</div>
        <div class="head_number">数量</div>
        <div class="head_number">金额</div>
        <div class="head_number">操作</div>
    </div>
    <div class="shop_box" v-for="(item,index) in shopCarData.listData">
        <div class="shop_head">
            <div class="checked_box_is" v-if="item.shopSelect==true" @click="shopSelect(index)"></div>
            <div class="checked_box_no" v-if="item.shopSelect==false" @click="shopSelect(index)"></div>
            <span>店铺:{{item.shopName}}</span>
        </div>
        <div class="" v-for="(item2,index2) in item.goodsList">
            <div class="head_choose_all">
                <div class="checked_box_is" v-if="item2.isSelect==true" @click="productSelect(index,index2)"></div>
                <div class="checked_box_no" v-if="item2.isSelect==false" @click="productSelect(index,index2)"></div>
                <img :src="item2.img" alt="" width="80" height="80">
            </div>
            <div class="head_info">{{item2.title}}</div>
            <div class="head_number">{{item2.sizeAndColor}}</div>
            <div class="head_choose_price">¥{{item2.price}}</div>
            <div class="head_number">
                <span class="number_add" @click="numberAdd(index,index2)"></span>
                <span>{{item2.number}}</span>
                <span class="number_less" @click="numberLess(index,index2)"></span>
            </div>
            <div class="head_number">{{item2.number*item2.price}}</div>
            <div class="head_number" @click="deleteShop(index,index2)">删除</div>
        </div>
    </div>
    <div class="shop_car_foot">
        <div class="foot_choose_all">全选</div>
        <div class="foot_delete" @click="deleteAll()">删除</div>
        <div class="foot_type_number">已选商品{{shopCarData.carData.number}}件</div>
        <div class="foot_amount">合计{{shopCarData.carData.price}}元</div>
    </div>
</section>

在 HTML 部分,我们结合之前的数据做了列表渲染和条件渲染。并且列表渲染是嵌套进行渲染,首先我们根据店铺的数据渲染有多少个店铺,然后再根据每个店铺中有多少个商品进行商品的渲染,然后再根据店铺的选中状态决定渲染的图片。这样的多重嵌套渲染在工作中将经常遇到。。在这里大家需要注意一点,如果最外层命名为 item,那么在第一层的时候,你的数据都是基于 item 的,所以在渲染第二层的时候就需要另取一个名字,不能与 item 相同,并且下标名也不能一。第二层的数据来源写法为第一层取的名字+对象。并且你取参数的时候也要区分好数据的层级。代码结构如下。

<div v-for="(item,index) in myData">
    <div>列表{{item}}</div>
    <div v-for="(item2,index2) in item.listData" v-if="item.isSelect==true">
        <div v-if="item2.isSelect==true">{{item2}}</div>
    </div>
</div>

当我们完成了页面,接下来就应该来完善功能了,在这里我们有以下几个功能。

1.通过店铺的选择按钮全选或者反选店铺中的所有产品,并计购物车中所有选中状态产品的价格及产品种类数量。

2.通过商品的选择按钮全选或者反选该产品,并计购物车中所有选中状态产品的价格及产品种类数量。

3.增加或者减少购物车中某个商品的数量,并实时计算出当前商品的总价,如果该商品为选中状态则实时计算购物车总价。

对于购物车商品的种类和价格的计算,需要去遍历我们的数据源,如果商品为选中状态就参与计算,将这个计算写成一个方法,在改变选中状态或者改变数量的时候调用此方法进行价格计算。

compute:function () {
    var price=0;
    var type=0;
    var data=this.shopCarData.listData;
    var dataLen=data.length;
    for(var i=0;i<dataLen;i++){
        var goodsData=data[i].goodsList;
        for(var j=0;j<goodsData.length;j++){
            if(goodsData[j].isSelect==true){
                type++;
                price+=goodsData[j].price*goodsData[j].number
            }
        }
    }
    this.shopCarData.carData.price=price;
    this.shopCarData.carData.number=type;
}

全选与反选都只需要对当前的状态进行判断,然后作出相对应的改变。有区别的地方在于,如果是店铺的按钮,你则需要对店铺所属的所有商品进行设置,而如果是商品的按钮,你只需要对当前这个商品进行设置,我们都通过传递下标来判断需要设置的是哪些数据。

shopSelect:function (index) {//店铺的选中按钮
    var data=this.shopCarData.listData[index];
    var list=data.goodsList;
    var listLen=list.length;
    var setCode;
    if(data.shopSelect==false){
        setCode=true
    }else {
        setCode=false
    }
    for(var i=0;i<listLen;i++){
        list[i].isSelect=setCode
    }
    this.shopCarData.listData[index].shopSelect=setCode;
    this.compute()//调用方法实时计算价格
},

productSelect:function (index,index2) {//商品的选中按钮
    var sta=this.shopCarData.listData[index].goodsList[index2].isSelect;
    if(sta==true){
        this.shopCarData.listData[index].goodsList[index2].isSelect=false;
    }else {
        this.shopCarData.listData[index].goodsList[index2].isSelect=true;
    }
    this.compute()//调用方法实时计算价格
},

在我们对商品数量进行更改的时候,整体与上一文讲的判断一致,及最小为1,最大为库存值。不过在这里需要在复杂的数据结构中设置这一个商品的数量,需要通过传递下标来进行设置。

numberAdd: function (index,index2) {
    var nowNumber = this.shopCarData.listData[index].goodsList[index2].number;
    var total = this.shopCarData.listData[index].goodsList[index2].total;
    nowNumber++;
    if (nowNumber < 1) {
         nowNumber = 1
    }
    if (nowNumber > total) {
        nowNumber = total
    }
    this.shopCarData.listData[index].goodsList[index2].number = nowNumber;
    this.compute()
},
numberLess: function (index,index2) {
    var nowNumber = this.shopCarData.listData[index].goodsList[index2].number;
    var total = this.shopCarData.listData[index].goodsList[index2].total;
    nowNumber--;
    if (nowNumber < 1) {
        nowNumber = 1
    }
    if (nowNumber > total) {
        nowNumber = total
    }
    this.shopCarData.listData[index].goodsList[index2].number = nowNumber;
    this.compute()
},

接下来就该是对商品的删除操作了。在商品列表中点击删除按钮,执行单个商品的删除。这个时候,我们也是通过传递下标来删除数据源中的对应数据,Vue.js 将会自动更新页面,从而删除商品列表中的数据。但由于我们的商品是基于店铺的,所以在删除商品之后需要进行判断,如果店铺里面商品数组的长度为0了,就把这个店铺也删除了。当然在实际工作中,你删除的时候需要弹出模态对话框,根据用户的操作来决定是否删除。

deleteShop:function (index,index2) {
    var data=this.shopCarData.listData[index].goodsList;
    var shopData=this.shopCarData.listData;
    data.splice(index2,1);
    if(data.length==0){
        shopData.splice(index,1);
    }
}

而全部删除按钮则是将所有用户选中的商品进行删除,在这里我们需要对数据进行循环判断。如果是选中,就删除该数据,同样的,如果删除之后店铺的商品为0,则店铺也需要删除。结合之前几个方法的思路,我想你应该已经可以写出这一功能了。

一个购物车就这样完成了,当然在实际工作中,往往会根据实际需求来对功能进行改变,需要开发者自己来构思这些功能,如果一直用别人的思路,是无法成长的。开发者在开发过程中积累的经验,往往都是后续工作中最宝贵的财富。

到本文为止,我们已经有了很多案例,Vue.js 的大多数使用情况都已经有了例子,但是它们都是一个个独立的案例,并没有合成一个整体,它们之间也没有关联起来,所以在接下来的内容中,我们将会把页面的内容贯穿在一起,让它们成为一个联动的内容。

上一篇
下一篇
目录