React == 实现简易版购物车
1、几个要点:
为了方便后面使用input type = "checkbox" 实现复选框的选中/不选中,给传递过来的属性要在遍历的时候,单独加上一个新属性 checked
count 属性 默认值 都是1.
state = {
all : false,
sumprice :0,
one : false,
sumcount:0
}
state对象 :
- all -----> 用来定义全选按钮
- sumprice -----> 用来定义总价
- one -----> 用来控制 结算按钮的样式(当选中的其中任何一条购物车条目时候,显示橘色,当没有任何一条选中,显示灰色)
- sumcount ----> 用来显示购物车的总数量,显示在页面中
2、单选框的实现
1)首先是渲染的都是同样的样式,所以在这里传递一个index特别关键,通过index的传递才能够知道操作的是哪条
2)当onchange事件发生的时候,对当前checked属性进行取反。list[index].checked = ! list[index].checked。
3)单选框决定全选框:使用了数组的every方法(只有数组的每一项都满足条件,才会返回true),用所有datalist的单选框都是true的时候,全选按钮才会为true
4)单选框的选中与否决定结算框的样式:one : list[index].checked // 为true的时候,one : true
//单选 handleChange(index){ var list = [...this.state.datalist] list[index].checked = !list[index].checked // every方法 var every=list.every((item,index)=>{ return item.checked==true; }) //单选框中如果有一个是 checked的是true就可以 var some = list.some((item,index)=>{ returnlist[index].checked }) this.setState({ datalist :list, all : every, //全选按钮,只有当所有的list[index]=== true 的时候才会返回true one : some //设定结算框的样式是哪个,根据list[index].checked }) this.SumPrice() }
3、全选按钮的实现
1)当点击全选框,对全选框的状态进行取反
2)点击全选按钮的时候,所有的单选框的为true / false 直接取决的 全选框按钮当前的状态true / false
遍历所有的list[i].checked = all , 把全选框的状态(true/false)直接赋值给所有的list[i].checked 。
3)当全选的时候,结算框的样式直接会跟随变动,当为false,即没有一个购物车条目呗选中,此时结算框的状态为灰色。当为true,结算框为橘色。
<input type="checkbox" onChange={()=>{this.handleAll()}} checked={this.state.all} value=""/> //全选 handleAll(){ var list = [...this.state.datalist] var all = this.state.all all = !all //onchange事件发生,就是对当前的状态进行取反 for(var i = 0 ; i < list.length ;i++){ list[i].checked =all // 全选框的状态直接影响所有的单选框,就把全选框的状态赋给所有的单选框即可 } this.setState({ all : all, one : all //全选的状态直接影响结算框的样式 }) this.SumPrice() }
4、购物车数量加减的实现
1)数量增加Add
重要的还是传递对应的index,才能准确地知道操作的是哪个购物车条目
list[index].count++
2)数量减少Minus
还有进行一步判断,当此时购物车的数量已经是1的时候,不允许再继续减了
list[index].count--
list[index].count<1?1:list[index].count
<button className={style.minus} onClick={()=>{this.handleMinus(index)}}>-</button> <input type="text" value={this.state.datalist[index].count||''}/> <button className={style.add} onClick={()=>{this.handleAdd(index)}}>+</button> //加 handleAdd(index){ //设定的value= {this.state.datalist[index].count} var list = [...this.state.datalist] list[index].count++; this.setState({ datalist : list, }) this.SumPrice() } //减 handleMinus(index){ //设定的value= {this.state.datalist[index].count} var list = [...this.state.datalist]; list[index].count--list[index].count=list[index].count<1?1:list[index].count; this.setState({ datalist : list }) this.SumPrice() }
5、总价的实现
1)遍历所有的datalist,只有当其中每一个checked属性为true的时候(表明已经被勾选上了,此时可以计算),才去计算金额
2)得到所有的总价,还能得到当前选中的数量一共有多少
SumPrice(){ var sum=0 var count = 0; var list = [...this.state.datalist] for(var i =0; i< list.length ;i++){ if(list[i].checked=== true){ sum += list[i].newprice *list[i].count count +=list[i].count } } this.setState({ sumprice : sum, sumcount : count //结算个数 }) }
6、当进行 数量 的增加、减少、单选按钮、全选按钮的时候 都要重新调用计算总价的函数。
=============================================================================
完整代码:
JS >
class CartPage extends Component { state ={ datalist:[ { "imgUrl":"https://wochu.oss-cn-hangzhou.aliyuncs.com/upload/c8db2f99-d79e-4c4a-97e8-3e95c67a3b2e.jpg", "name": "小青菜350g", "newprice" : "4.5", "oldprice" : "4.9", "checked" :false, "count" :1}, { "imgUrl":"https://img.wochu.cn/upload/abbc6852-711f-4d09-8e61-216c13505ccd.jpg", "name": "洪湖渔家香辣大闸蟹500g", "newprice" : "15.9", "oldprice" : "39.9", "checked" :false, "count" :1 }, { "imgUrl":"https://wochu.oss-cn-hangzhou.aliyuncs.com/upload/c8db2f99-d79e-4c4a-97e8-3e95c67a3b2e.jpg", "name": "小青菜350g", "newprice" : "4.5", "oldprice" : "4.9", "checked" :false, "count" :1 }, ], all : false, sumprice :0, one : false, sumcount:0} render() { return( <div className={style.cartList}> <div className={style.cartListItem}> <ul className={style.shopList} ref="myul">{/*对应的每个购物车条目 */} { this.state.datalist.map((item,index)=> <li key={index}> <input type="checkbox" className={style.checkbtn+' '+style.UnChecked} ref="mytext"onChange={()=>{this.handleChange(index)}} checked={item.checked} value="" /> <div className={style.shopImg}>{/*点击图片跳转到页面详情 */} <div className={style.shopImgShow}> <img src={item.imgUrl} alt=""/> </div> </div> {/*商品详情 */} <div className={style.shopInfo}> <div className={style.shopTitle}>{item.name}</div> <div className={style.shopCoupen}></div> <div className={style.shopPrice}> <div className={style.price}> <span>¥{item.newprice}</span> <i>¥{item.oldprice}</i> </div> <div className={style.shopSelect}> <button className={style.minus} onClick={()=>{this.handleMinus(index)}}>-</button> <input type="text" value={this.state.datalist[index].count||''}/> <button className={style.add} onClick={()=>{this.handleAdd(index)}}>+</button> </div> </div> </div> </li> ) } </ul> </div> <div className={style.sum}> <input type="checkbox" onChange={()=>{this.handleAll()}} checked={this.state.all} value=""/> <div className={style.checkPrice}>{/*合算 */} <div className={style.totalPrice}> <span className={style.allsum}>合计</span> <span>¥{this.state.sumprice}</span> </div> {/*不含运费 */} <div className={style.fee}>(不含运费)</div> </div> {/*结算按钮 */} <div className={this.state.one?style.btnCheck:style.btnNoCheck}>结算 <span>({this.state.sumcount})</span> </div> </div> </div> ); } //单选 handleChange(index){ var list = [...this.state.datalist] list[index].checked = !list[index].checked var every=list.every((item,index)=>{ return item.checked==true; }) //单选框中如果有一个是 checked的是true就可以 var some = list.some((item,index)=>{ returnlist[index].checked }) this.setState({ datalist :list, all : every, one : some //设定结算框的样式是哪个,根据list[index].checked }) this.SumPrice() } //全选 handleAll(){ var list = [...this.state.datalist] var all = this.state.all all = !all for(var i = 0 ; i < list.length ;i++){ list[i].checked =all } this.setState({ all : all, one : all //全选的状态直接影响结算框的样式 }) this.SumPrice() } handleAdd(index){ //设定的value= {this.state.datalist[index].count} var list = [...this.state.datalist] list[index].count++; this.setState({ datalist : list, }) this.SumPrice() } handleMinus(index){ //设定的value= {this.state.datalist[index].count} var list = [...this.state.datalist]; list[index].count--list[index].count=list[index].count<1?1:list[index].count; this.setState({ datalist : list }) this.SumPrice() } SumPrice(){ var sum=0 var count = 0; var list = [...this.state.datalist] for(var i =0; i< list.length ;i++){ if(list[i].checked=== true){ sum += list[i].newprice *list[i].count count +=list[i].count } } this.setState({ sumprice : sum, sumcount : count //结算个数 }) } } export default CartPage;
CSS >
.cartList{background:#f4f5f7;width:100%;top:.99rem;.cartListItem{ width:100%;background:#fff;margin-bottom:.04rem; // 购物车列表 .shopList{ width:100%;// height:1.11rem;padding:0 .09rem;background:#fff;li{ width:100%;height:1.11rem;border-bottom:1px solid #e6e6e6;background:#fff;// 选中按钮 .checkbtn{ width:.17rem;height:1.11rem;float:left; } // 选中时候的类名 .UnChecked{background:url("../../../image/cart-img/unselect.png") no-repeat;background-size:100% .25rem; } // 点击图片跳转 .shopImg{width:1.1rem;height:1.1rem;margin:0 .1rem;float:left;.shopImgShow{ width:1.1rem;height:1.1rem;img{ width:100%; }} } // 购物车商品详情 .shopInfo{width:2.08rem;height:1.1rem;padding:.1rem 0;float:left;.shopTitle{ width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;height:.3rem;font-size:.14rem; }.shopCoupen{width:2.08rem;height:.12rem;margin:.1rem 0; }.shopPrice{width:2.08rem;height:.25rem;//价格 .price{ width:1.08rem;height:.21rem;float:left;span{ font-size:.15rem;color:#f96d16; }i{font-size:.13rem;color:#999;text-decoration:line-through;font-style:normal; }} // 按钮 .shopSelect{float:right;width:.775rem;height:.25rem; .minus{ float:left;width:.225rem;height:.25rem;border:0; }input{float:left;width:.325rem;height:.25rem;text-align:center;border:0; }.add{float:left;width:.225rem;height:.25rem;border:0; }} } } } } } // 合算 div.sum{width:100%;height:.5rem;background:#fff;padding-left:.1rem;position:fixed;bottom:.5rem;left:0; input{ height:100%;float:left; }.checkPrice{float:left;width:1.48rem;height:.41rem;line-height:.41rem;padding:.08rem 0;margin-left:.1rem;// 合计 .totalPrice{ float:left;width:.869rem;height:.36rem;line-height:.36rem;font-size:.16rem;color:#f96d16;.allsum{ font-size:.13rem;color:#333; }} // 不含运费 .fee{float:left;width:.61rem;font-size:.13rem;color:#999; }} // 结算按钮 .btnCheck{width:1.15rem;height:.49rem;background:rgb(249, 109, 22);float:right;line-height:.49rem;font-size:.18rem;color:#fff;text-align:center; }.btnNoCheck{width:1.15rem;height:.49rem;background:rgb(153, 153, 153);float:right;line-height:.49rem;font-size:.18rem;color:#fff;text-align:center; }} }