vant 实现全选功能

今天遇到了一个问题。实现类似淘宝的购物车全选/全不选效果。记录下这里面的问题:

vant 实现全选功能_第1张图片

这里面有这样几成逻辑:(我们把图中的京东,网易,天猫等看成一个模块)

1每一个单独模块有一个控制该模块是否全选的按钮,点击全选/全不选切换,该模块下的所有复选框要被勾选/全不勾选

同时每一个模块的全选/全不选按钮也会影响到整个页面最底部的全选按钮状态,当每个模块都会全选状态时,整个页面底部的全选按钮将被勾选

2每一个单独模块下的复选框被逐一勾选时,它会影响到两层元素,其一是它所在的模块。当全部被勾选时,该复选框所在模块的全选按钮将被勾选,其二,所有复选框被逐一勾选时,整个页面底部的全选按钮将被勾选

所以对于每一个复选框按钮,它将都会影响到两层元素。

我们先看一看大致结构:

vant 实现全选功能_第2张图片

注意:单个模块复选框我们利用van-check-group进行包裹。再看一看数据结构

vant 实现全选功能_第3张图片

每一个模块对应一条json,其中有两个非常重要的属性:isChecked,它用来控制当前模块的选中状态,另一个就是result:它用来记录单个模块中有多少个复选框被勾选了。我们在van-checkbox-group中通过v-model进行了绑定。

代码如下:

vant 实现全选功能_第4张图片

vant 实现全选功能_第5张图片

vant 实现全选功能_第6张图片

这里有2个地方需要解释:

1 result用途到底是啥?

van-checkbox-group的change事件会有一个v-model绑定的值。它的值是一个数组,记录了当前哪些复选框被选中了。我们不用官方写法。把result写在data里。因为所有的模块是循环出来,每一个模块我们都需要知道该模块下到底选中了哪些复选框,所以我们把result写在了arr数组的每一个json里。

2 如下代码到底是啥意思?

item.list.forEach(j=>{

item.result.push(j.title)

})

我们可以这么理解。它就是全选。因为对每一个模块来说,勾选一个,当前模块的result数组就添加了一个。反过来,当当前模块的result都被添满。也就是result的长度和当前模块(arr下的json下list)长度一致的时候。就表明全选了

这个效果已经实现了。但是它需要有两个依赖条件:

1 数据结构需要用这种格式

2 我们对van-checkbox-group需要通过v-model绑定result,而不是其他

知道了基本的套路。我们接下来需要完成类似淘宝的购物车的完整功能。截图如下:

vant 实现全选功能_第7张图片

vant 实现全选功能_第8张图片

vant 实现全选功能_第9张图片

新的功能点包括如下几个:

1当只勾选一个模块内的商品,比如只勾选了京东里的商品。直接跳转至结算页面,如果至少勾选了2个模块,比如同时勾选了京东和天猫的商品,则有一个弹出层,提示单独结算。

2底部结算和合计的数字需要实时统计。实时计算(注意:结算按钮的数字不是统计所有勾选项,而是统计品类,比如本例中网易,天猫,京东等模块。如果有京东商品被勾选,则结算显示的数字是1.如果京东,天猫两个类目商品被勾选则结算按钮的值是2,依次类推)

3删除按钮点击时需要知道当前被勾选的那个品类的那个商品

针对第一个功能。先理清下思路:

(1)弹出层出现的条件就是至少勾选2个大类模块。那如何知道至少勾选了至少2个大类呢?

每次勾选商品。都会被van-checkbox-group里change事件所监听。我们知道,每个大类模块(比如京东)映射的json下都有一个

result:[],表示当前模块下哪个商品被勾选。也就是说只要有大类模块下有商品被勾选,其对应的json下的result数组的长度是不为空的。所有我们其实可以遍历整个大的数组,再去判断每一个json下的result的值是否有值。同时定义一个局部变量num,在遍历的过程中,只要当前json下的result数组有值,就累加。这样如果京东,网易和天猫这三个模块里都有商品被勾选,那么说明这三个json里的result的值都是不为空的。那累加的num就是3,那这个num就和结算的值是吻合的。

而合计的值又怎么计算呢?合计的值其实就是每一个商品的数量乘其单价,最后把所有勾选项的这些值累加。

同样的道理:我们需要一个条件。我们需要知道哪些商品被勾选了,如果能提供一个所有被勾选商品的集合,我们在他里面做文章,这个事情就好办了。

而恰好。result为我们提供了这个桥梁。所有道理是一样的。每次商品被勾选,每个大类json下的result就会记录当前被勾选的数据。如果我们循环整个大的数组,再遍历每一个json的下result,最后把他们push到一个数组里。那这个数组不就记录了所有被勾选的对象。但是有一点,此时我们需要做一点改变。van-checkbox-group下的van-checkbox的name不再和某一个属性,比如id等进行双向绑定,而是直接绑定item。这样result数组里出现的就是所有被勾选的item,每一个item记录了所有的数据,当然就有数量和价格。那总价就出来了。

而如何在勾选的时候合计的值及时更新呢?因为每次勾选都会被van-checkbox-group的change实践监听到。所以只需要在这个事件中再执行下我们上面的逻辑即可?如何在点击+、-按钮时同步更新合计值呢?道理一样。

代码如下:

vant 实现全选功能_第10张图片

vant 实现全选功能_第11张图片

 

vant 实现全选功能_第12张图片

vant 实现全选功能_第13张图片

vant 实现全选功能_第14张图片

vant 实现全选功能_第15张图片

完整代码如下:

.shoppingCartpage{box-shadow:0px 2px 6px 0px rgba(51,51,51,0.04);border-radius:20px;background:#F6F6F7FF;min-height: 100vh}

.header{width: 100%; height: 170px;position: relative;overflow:hidden;padding: 0;margin: 0;}

.header::after{width: 140%;height: 170px;position: absolute;top:0;left:-20%;content: "";

;display: block;border-radius: 0 0 50% 50%;background:var(--themeBgColor);} 

.main{margin:-100px auto 0 auto;width: 702px;background: transparent;padding-bottom:273px;position: relative;z-index:1}

.footer{width: 100%; height: 101px;position: fixed;bottom:97px;left: 0;z-index: 2;padding: 10px 24px}

.checkAll{float: left;width: 40%;height: 100%}

.accountBox{float: left;width: 60%;display: flex;justify-content: flex-end}

.account {width:190px;height:80px;background:var(--themeBgColor);border-radius:40px;}

.h{height: 70px;}

.tipBox{width: 100%;}

.white{color:#fff}

.num{height: 101px;line-height: 80px}

.btn{width: 190px; height: 60px;line-height:60px;border-radius:40px;text-align: center}

.move{background: var(--themeBgColor);color:#fff}

.del{border:1px solid var(--themeBgColor);background: #fff;color:var(--themeBgColor)}

.point{color:var(--themeBgColor);margin-right:5px}

.gray{color:#999999FF}

.main{

    .item{background:#fff;} 

    .title{display: flex; height: 40px;line-height: 40px}

    .classify{flex:0 0 220px}

    .freeInfo{flex:1 0 auto;display:flex;justify-content: flex-end}

    .mt51{margin-top:51px}

    .thumbnail{width: 185px; height: 185px;display: block}

    .rd{width: 40px; height: 40px;border:1px solid #999999FF;background: #fff;position: relative;cursor: pointer;}

    .rd::after{display: block;width: 40px; height: 40px;position: absolute;top:0;left: 0;background: #fff;visibility: visible;}

    .btn{width: 40px; height: 40px;}

    .input{width:80px; height: 37px;border-right:1px solid #CCCCCCFF;;border-left:1px solid #CCCCCCFF;}

    .mt50{margin-top:50px}

    .dis{display: inline-block}

    .btnOuter{display: flex;justify-content: flex-end}

    .btnInner{width: 168px;border:1px solid #CCCCCCFF;}

    .num{margin-right:6px}

    

}

.pupTitle{  height: 180px;border-bottom: 1px solid #eee;

            .tit{height: 98px;line-height:98px}

            .mt10{margin-top:10px}

        }

.pupTitle p{text-align: center}

.texColor{color:#7B7B7BFF}

.h100{ height: 100px;}

.pupCont p{font-size:24px;color:#999999FF }

.pupCont div{font-size:26px;color:#333333FF;font-weight: 500%}

.ml16{margin-left:16px;}

.pupCont span{display: inline-block}

.theme{color:var(--themeBgColor)}

你可能感兴趣的:(vant,vue)