vue从创建到完整的饿了么(17)本地缓存实现购物车

编程入门 行业动态 更新时间:2024-10-26 00:28:09

vue从创建到完整的饿了么(17)本地缓存实现<a href=https://www.elefans.com/category/jswz/34/1770732.html style=购物车"/>

vue从创建到完整的饿了么(17)本地缓存实现购物车

说明

1.上一章--watch监听子路由
2.苍渡大神源码--项目源码地址
3.数据接口--API接口
4.UI框架--Mint UI
5.下一章--购物车的详细信息展示与删除

开始

1.先看一下目前的UI图

要实现的UI图

2.footdiv代码修改如下

<transition name="left"><div v-if="footdiv" class="foot on"><div class="footleft"><div class="footlogo"><icon name="footcar" class="footicon"></icon><div class="rednum">15</div></div><div class="footmain"><div v-if="false" class="">未选购商品</div><div class="ih30 fs1-2">¥ 3205</div><div class="ih20">配送费 ¥5</div></div></div><div class="footright"><span >¥20起送</span><span v-if="false">还差¥15起送</span><span v-if="false">去结算</span></div></div>
</transition>

css如下

.foot{height:50px;line-height:50px;background-color:#594C46;display:flex;position:fixed;bottom:0px;left:0px;width:100%;
}
.foot.on .footicon{color:#fff;
}
.foot.on .footmain{color:#fff;
}
.foot.on .footlogo{background-color:#3190E8;
}
.foot.on .footright{color:#fff;
}
.footleft{flex:2;display:flex;
}
.footright{flex:1;text-align:center;color:#B7B7B7;background-color:#61686A;
}
.footright.on{background-color:#4CD964;color:white;
}
.footlogo{text-align:center;width:50px;height:50px;border-radius:50%;background-color:#515151;margin:0px 10px;border:3px solid #444446;transform:translatey(-15px)
}
.footicon{color:#8a8a8a;width:40px;height:40px;margin-top:7px;
}
.footmain{height:50px;color:#ADADAD;font-size:0.8rem;
}
.rednum{position: absolute;top:-3px;right:-5px;border-radius:50%;background-color:red;color:white;height:18px;width:18px;text-aligin:center;line-height:18px;font-size:12px;
}

我把所有可能出现的元素全部写出来了,用v-if来判断显示哪个,到时候购物车有东西了,直接给footdiv加一个onclass就行。

3.点击添加
注意,首先我们要把布局修改一下

以前绿色的div在红色的div内,而红色div有一个点击跳转的效果,所以点击绿色div也会跳转。这在js中解决非常简单,但是在vue中怎么解决呢?我上网查了查没找到结果(哪位老铁知道怎么解决感谢指出)。。。最后是用布局解决的。
解决后红色div与绿色div是兄弟并不是父子,将绿色div定位到红色div上即可。

4.数据类型
咱们把数据存到localStorage里,键名为mycar,键值结构为

[{"shop":第一个商品的相关信息,"num":第一个商品的个数},{"shop":第二个商品的相关信息,"num":第二个商品的个数}]

(注意:localStorage只接收字符串,所以咱们存取都要先转化再使用)
(注意:下面点击事件的参数e为API返回的一个完整的食品对象,狠狠的点击这里查看API,截图如下)

点击事件如下

addcar:function(e){var that=this;if(localStorage.getItem("mycar")){var mycar=JSON.parse(localStorage.getItem("mycar"));var addok=true;                                              //数据是否添加for(var i =0;i<mycar.length;i++){if(mycar[i].shop.item_id==e.item_id&&mycar[i].shop.category_id==e.category_id&&mycar[i].shop.restaurant_id==e.restaurant_id){mycar[i].num=mycar[i].num+1;addok=false;break;}}if(addok){mycar.push({"shop":e,"num":1});}that.mycar=mycar;localStorage.setItem("mycar",JSON.stringify(mycar));}else{var mycar=[{"shop":e,"num":1}];that.mycar=mycar;localStorage.setItem("mycar",JSON.stringify(mycar));}}

(注意:别忘了在data中设置变量mycar来存放购物车信息)
footdiv中监听mycar来控制onclass是否添加和右上角的红色数字是否显示。

<transition name="left"><div v-if="footdiv" class="foot" :class="{on:mycar.length>=1}"><div class="footleft"><div class="footlogo"><icon name="footcar" class="footicon"></icon><div v-if="mycar" class="rednum">15</div></div><div class="footmain"><div v-if="false" class="">未选购商品</div><div class="ih30 fs1-2">¥ 3205</div><div class="ih20">配送费 ¥5</div></div></div><div class="footright"><span >¥20起送</span><span v-if="false">还差¥15起送</span><span v-if="false">去结算</span></div></div></transition>

这时发现商品数量没有计算,目前是写死的15,在计算属性computed中添加计算

computed:{//计算属性mycarshopnum:function(){var num=0;for(var i=0;i<this.mycar.length;i++){num+=this.mycar[i].num;}return num}},

footdiv中的rednum调用

<div v-if="mycar" class="rednum">{{mycarshopnum}}</div>

ok!运行试试

解决!

修改

1.可以看到,除了商品数量,其他全是假的,咱们现在写活。
computed中添加商品价格的计算(piecewise_agent_fee.tips为配送费,float_minimum_order_amount为起送费,在商家详情的API中,咱们以前已经获取)

 computed:{//计算属性//计算商品数量mycarshopnum:function(){var num=0;for(var i=0;i<this.mycar.length;i++){num+=this.mycar[i].num;}return num},//计算商品价格(商品只有一个种类)mycarshoppic:function(){var num=0;for(var i=0;i<this.mycar.length;i++){num+=(this.mycar[i].shop.specfoods[0].price*this.mycar[i].num);}return num},//判断商家起送价与目前购物车价格shoppicbig:function(){if(this.mycar){if(this.mycarshoppic>=this.shopinfo.float_minimum_order_amount){return 1}else{return 2}}else{return false}}},

footdiv修改如下

<transition name="left"><div v-if="footdiv" class="foot" :class="{on:mycar.length>=1}"><div class="footleft"><div class="footlogo"><icon name="footcar" class="footicon"></icon><div v-if="mycar" class="rednum">{{mycarshopnum}}</div></div><div class="footmain"><div v-if="!mycar" class="">未选购商品</div><div v-if="mycar" class="ih30 fs1-2">¥ {{mycarshoppic}}</div><div v-if="mycar" class="ih20">{{this.shopinfo.piecewise_agent_fee.tips}}</div></div></div><div class="footright" :class="{on:shoppicbig==1}"><span v-if="!mycar">¥{{this.shopinfo.float_minimum_order_amount}}起送</span><span v-if="shoppicbig==2">还差¥{{this.shopinfo.float_minimum_order_amount-mycarshoppic}}起送</span><span v-if="shoppicbig==1">去结算</span></div></div></transition>

运行试试

商品数量

现在只有购物车显示总数量,每个商品显示几个并没有。
1.样式

<transition name="right"><span  class="ih20"><span><icon class="addicon" name="offline"></icon></span><span class="ih20 inblock y-4">15</span></span></transition>

因为商品数量为0时,减号也该没有,所以商品数量与减号写在一个动画内了,样式如下

2.判断商品数量。
现在商品的信息是从接口请求到后直接渲染在页面,没有做任何处理。现在我们要把商品信息与购物车的信息结合一下,在computed写函数(shopmean是从接口请求到的商品信息,在前几章已经请求到,未做任何处理。specfoods是商品的型号,这里默认只有一个)

 //商品与购物车数量结合getshopnum:function(){for(var i=0;i<this.shopmean.length;i++){for(var k=0;k<this.shopmean[i].foods.length;k++){for( var h=0;h<this.mycar.length;h++){if(this.shopmean[i].foods[k].specfoods[0]._id==this.mycar[h].shop.specfoods[0]._id){this.shopmean[i].foods[k].mynum=this.mycar[h].num;}}}}return this.shopmean}

再然后我们在页面渲染数据时,只需要把

v-for="item in shopmean"

改成

v-for="item in getshopnum"

即可。
最后判断减号与数量的显示隐藏

<transition name="right"><span v-if="items.mynum" class="ih20"><span><icon class="addicon" name="offline"></icon></span><span class="ih20 inblock y-4">{{items.mynum}}</span></span>
</transition>

运行试试

除了动画没有运行,其他的完美!

删除商品

1.删除点击事件在dome绑定

<transition name="right"><span v-if="items.mynum" class="ih20"><span @click="removecar(items)"><icon class="addicon" name="offline"></icon></span><span class="ih20 inblock y-4">{{items.mynum}}</span></span>
</transition>

methods中写函数

removecar:function(e){for(var i=0;i<this.mycar.length;i++){if(this.mycar[i].shop.specfoods[0]._id==e.specfoods[0]._id){this.mycar[i].num==1?this.mycar.splice(i,1):(this.mycar[i].num=this.mycar[i].num-1);break;}}localStorage.setItem("mycar",JSON.stringify(this.mycar));}

注意
这里要改一下计算属性中的getshopnum函数。咱们在刚开始写时,只是把商品列表跟购物车列表循环,当ID相同时在商品列表添加属性mynum存储商品在购物车数量,不相同时不作操作。但是,我们做了减商品的功能后,当商品数量为1时,减一后购物车清除该商品,然后通过计算属性中的getshopnum函数与商品列表循环,结果因为购物车已经清除该商品而函数找不到相同ID不作任何操作,但商品列表的该商品数量仍为一,所以当ID不相同时我们给商品列表自定义属性mynum为0即可,将computed中的getshopnum修改为

//商品与购物车数量结合getshopnum:function(){for(var i=0;i<this.shopmean.length;i++){for(var k=0;k<this.shopmean[i].foods.length;k++){var isadd=true;                          //判断该商品是否在购物车for( var h=0;h<this.mycar.length;h++){if(this.shopmean[i].foods[k].specfoods[0]._id==this.mycar[h].shop.specfoods[0]._id){this.shopmean[i].foods[k].mynum=this.mycar[h].num;isadd=false;break;}}if(isadd){this.shopmean[i].foods[k].mynum=0;}}}return this.shopmean}

注意
当购物车清空时,mycar已存在而不是刚开始的空,所以购物车div里的元素显示隐藏要修改为判断mycar的长度而不是是否为空

<transition name="left"><div v-if="footdiv" class="foot" :class="{on:mycar.length>=1}"><div class="footleft"><div class="footlogo"><icon name="footcar" class="footicon"></icon><div v-if="mycar.length" class="rednum">{{mycarshopnum}}</div></div><div class="footmain"><div v-if="!mycar.length" class="">未选购商品</div><div v-if="mycar.length" class="ih30 fs1-2">¥ {{mycarshoppic}}</div><div v-if="mycar.length" class="ih20">{{this.shopinfo.piecewise_agent_fee.tips}}</div></div></div><div class="footright" :class="{on:shoppicbig==1}"><span v-if="!mycar">¥{{this.shopinfo.float_minimum_order_amount}}起送</span><span v-if="shoppicbig==2">还差¥{{this.shopinfo.float_minimum_order_amount-mycarshoppic}}起送</span><span v-if="shoppicbig==1">去结算</span></div></div></transition>

运行试试

商品分类小红点

我们只需要在getshopnum给商品判断购物车中给商品数量时,给该商品的分类也加上该商品的数量即可。修改如下

//商品与购物车数量结合getshopnum:function(){for(var i=0;i<this.shopmean.length;i++){var thisnum=0;for(var k=0;k<this.shopmean[i].foods.length;k++){var isadd=true;                          //判断该商品是否在购物车for( var h=0;h<this.mycar.length;h++){if(this.shopmean[i].foods[k].specfoods[0]._id==this.mycar[h].shop.specfoods[0]._id){this.shopmean[i].foods[k].mynum=this.mycar[h].num;thisnum+=this.mycar[h].num;isadd=false;break;}}if(isadd){this.shopmean[i].foods[k].mynum=0;}}this.shopmean[i].mynum=thisnum;}return this.shopmean}

结果如下

ok!购物车表面功夫写完了,下面升级购物车。
注意
购物车应该在渲染页面事就获取数据,所以在mounted中添加

 //获取购物车信息if(localStorage.getItem("mycar")){that.mycar=JSON.parse(localStorage.getItem("mycar"));}

最终shop.vue代码修改如下

<template><div id="shop" class="bgfff"><transition name="left"><div v-if="myrouter" class="big"><div class="topbg"><img class="topbgimg" :src="imgpath+shopinfo.image_path"></div><div class="shoptop"><div class="toptop ih30"><router-link to="/miste"><icon class="backicon" name="back"></icon></router-link><span class="right"><icon class="backicon2" name="cart"></icon><icon class="backicon2" name="more"></icon> </span></div><div class="topfoot"><div class="topleft"><img :src="imgpath+shopinfo.image_path"></div><div class="topright nowarp"><router-link to="shop/shopDetail"><div class="foota"><div class="footamain fs1-2 nowarp">{{shopinfo.name}}</div><icon name="right" class="icon3"></icon></div></router-link><div class="footb nowarp"><div class="nowarp">公告:{{shopinfo.promotion_info}}</div></div><div class="footc"><span class="footcmain"><span v-if="shopinfo.delivery_mode">{{shopinfo.delivery_mode.text}}•</span><span>约{{shopinfo.order_lead_time}}</span></span></div></div></div></div><div class="shopmid mgtop10"><div @click="modal=true" v-if="shopinfo.activities" class="midtop"><span class="te mgr5">{{shopinfo.activities[0].icon_name}}</span><span>{{shopinfo.activities[0].description}}</span><span class="right">{{shopinfo.activities.length}}个活动 <icon name="down" class="icon4"></icon></span></div><div class="mytab"><div @click="footdiv=shoporscore=true" :class="{ on:shoporscore }">商品</div><div @click="footdiv=shoporscore=false" :class="{ on:!shoporscore }">评价{{shopinfo.rating}}分</div></div></div><transition name="left"><div v-if="shoporscore" class="shopmain"><div class="mianleft"><div v-for="(item,index) in getshopnum" @click="itemgo(index)" :class="{on:index==shopon}" class="relative leftdiv"><div><icon v-if="index==0" class="icon5" name="hot"></icon><icon v-if="index==1" class="icon5" name="discount"></icon><span class="fs0-8">{{item.name}}</span><span v-if="item.mynum" class="rednum2">{{item.mynum}}</span></div></div></div><div class="mainright"><div class="item" v-for="item in getshopnum"><div class="itemtop padtop10 ih30 after"><span class="fs15">{{item.name}}</span><span class="fs0-8 col9f">{{item.description}}</span></div><div class="itemmain"><div v-for="items in item.foods" class="after"><router-link to="/shop/foodDetail"><div class="iteminfo"><div class="infoimgbox"><img :src="imgpath+items.image_path"></div><div class="inforight nowarp"><div class="colblack fs15 ih20 nowarp">{{items.name}}</div><div class="ih15 col9f"><span class="fs10 mgl">{{items.tips}}</span></div><div class="ih15"><span v-if="false" class="fs10 mgl"><span class="zk">包装费</span><span class="yh">{{}}</span></span></div><div class="ih20"><span class="colred fs12">¥</span><span class="colred mgr5">{{items.specfoods[0].price}}</span><span v-if="items.specfoods[0].original_price" class="fs12 col9f midline">¥56</span></div></div></div></router-link><div class="iteminfofoot ih20"><transition name="top"><span v-if="items.mynum" class="ih20"><span @click="removecar(items)"><icon class="addicon" name="offline"></icon></span><span class="ih20 inblock y-4">{{items.mynum}}</span></span></transition><span v-if="items.specfoods.length==1" @click="addcar(items)" class=""><icon name="add" class="addicon"></icon></span><span class="fs12 right gz" v-if="items.specfoods.length>1">选规则</span></div></div></div></div></div></div></transition><transition name="right"><div class="score" v-if="!shoporscore"><div class="scoretop"><div class="scoretopleft"><div class="fs1-2 colf60">{{shopinfo.rating}}</div><div class="fs15 col9f">综合评价</div><div class="fs0-8 col9f">高于周边商家{{parseInt(scoreratingpare_rating*100)}}%</div></div><div class="scoretopright"><div><span class="fs15 col9f mgr5">评价服务</span><stars :num="scorerating.service_score.toFixed(1)"></stars><span class="colf60 right">{{scorerating.service_score.toFixed(1)}}</span></div><div><span class="fs15 col9f mgr5">菜品评价</span><stars :num="scorerating.food_score.toFixed(1)"></stars><span class="colf60 right">{{scorerating.food_score.toFixed(1)}}</span></div><div><span class="fs15 col9f mgr5">送达时间</span><span class="fs15 colf60">{{scorerating.deliver_time}}分钟</span></div></div></div><div class="scoremain"><div class="scoremaintop after"><div v-for="(item,index) in scoretags" class="ih30 fs0-8" :class="{sty2:item.unsatisfied,sty1:!(item.unsatisfied),on:index==scoreindex}">{{item.name}}({{item.count}})</div></div><div class="scoremaininfo"><div v-for="item in score" class="scoreitem after"><div class="scoreitemleft"><img :src="imgaddpath(item.avatar)" ></div><div class="scoreitemright fs12 col9f"><div><span>{{item.username}}</span><span class="right">{{item.rated_at}}</span></div><div><stars :num="item.rating_star"></stars></div><div>{{item.time_spent_desc}}</div><div class="scoreimgbox"><img v-for="itema in item.item_ratings" :src="imgaddpath(itema.image_hash)"></div><div class="namebox"><div v-for="itemb in item.item_ratings">{{itemb.food_name}}</div></div></div></div></div></div></div></transition><transition name="top"><div v-if="modal" class="modal flex2 colfff pad10"><div class="modaltop flex1"><div><div class="modaltitle">{{shopinfo.name}}</div><div class="modalmid"><div class="modal_title ih30"><span>优惠信息</span></div><div><div v-if="shopinfo.activities" v-for="item in shopinfo.activities" class="midtop"><span class="te mgr5">{{item.icon_name}}</span><span>{{item.description}}</span></div></div></div><div class="modalinfo mgtop40"><div class="modal_title ih30"><span>商家公告</span></div><div> {{shopinfo.promotion_info}}  </div></div></div></div><div @click="modal=false" class="modalfoot"><span>X</span></div></div></transition><load v-if="num!=1"></load></div></transition><transition name="left"><div v-if="footdiv" class="foot" :class="{on:mycar.length>=1}"><div class="footleft"><div class="footlogo"><icon name="footcar" class="footicon"></icon><div v-if="mycar.length" class="rednum">{{mycarshopnum}}</div></div><div class="footmain"><div v-if="!mycar.length" class="">未选购商品</div><div v-if="mycar.length" class="ih30 fs1-2">¥ {{mycarshoppic}}</div><div v-if="mycar.length" class="ih20">{{this.shopinfo.piecewise_agent_fee.tips}}</div></div></div><div class="footright" :class="{on:shoppicbig==1}"><span v-if="shoppicbig==3">¥{{this.shopinfo.float_minimum_order_amount}}起送</span><span v-if="shoppicbig==2">还差¥{{this.shopinfo.float_minimum_order_amount-mycarshoppic}}起送</span><span v-if="shoppicbig==1">去结算</span></div></div></transition><router-view></router-view></div>
</template><script>
import stars from '../../components/stars/stars'
import load from '../../components/load/load'export default {data () {return {mycar:"",                                 //我的购物车footdiv:true,                             //脚部购物车是否显示shopon:0,                                 //商品种类选中的哪个imgpath:':8001/img/',    //商家头像的路径地址pathshopinfo:"",                              //商家信息shopmean:"",                              //食品信息shoporscore:true,                         //商家还是评价score:"",                                 //评价信息scorerating:"",                           //评价分数  scoretags:"",                             //评价分类scoreindex:0,                             //选中第几个评价分类num:1,modal:false,                              //模态框显示隐藏myrouter:true,                            //是否显示big div}},components:{//注册组件stars,load},mounted:function(){//生命周期var that=this;//获取购物车信息if(localStorage.getItem("mycar")){that.mycar=JSON.parse(localStorage.getItem("mycar"));}that.num=that.num-5;//餐馆详情this.$http.get(':8001/shopping/restaurant/'+this.$store.state.shopid+'').then(response => {console.log(response);this.shopinfo=response.body;that.num=that.num+1;}, response => {that.num=that.num+1;console.log(response);});//食品详情this.$http.get(':8001/shopping/v2/menu?restaurant_id='+this.$store.state.shopid+'').then(response => {console.log(response);that.num=that.num+1;this.shopmean=response.body;}, response => {that.num=that.num+1;console.log(response);});//评论详情this.$http.get(':8001/ugc/v2/restaurants/'+this.$store.state.shopid+'/ratings?offset=0&limit=10').then(response => {console.log(response);that.num=that.num+1;this.score=response.body;}, response => {that.num=that.num+1;console.log(response);});//评论分数this.$http.get(':8001/ugc/v2/restaurants/'+this.$store.state.shopid+'/ratings/scores').then(response => {console.log(response);this.scorerating=response.body;that.num=that.num+1;}, response => {console.log(response);that.num=that.num+1;});//评论分类this.$http.get(':8001/ugc/v2/restaurants/'+this.$store.state.shopid+'/ratings/tags').then(response => {console.log(response);this.scoretags=response.body;that.num=that.num+1;}, response => {console.log(response);that.num=that.num+1;});let mydiv=document.querySelector('.mainright');mydiv.addEventListener('scroll', this.handleScroll);},computed:{//计算属性//计算商品数量mycarshopnum:function(){var num=0;for(var i=0;i<this.mycar.length;i++){num+=this.mycar[i].num;}return num},//计算商品价格(商品只有一个种类)mycarshoppic:function(){var num=0;if(this.mycar.length){for(var i=0;i<this.mycar.length;i++){num+=(this.mycar[i].shop.specfoods[0].price*this.mycar[i].num);}};          return num;},//判断商家起送价与目前购物车价格shoppicbig:function(){if(this.mycarshoppic>=this.shopinfo.float_minimum_order_amount){return 1}else if(this.mycarshoppic==0){return 3}else{return 2}},//商品与购物车数量结合getshopnum:function(){for(var i=0;i<this.shopmean.length;i++){var thisnum=0;for(var k=0;k<this.shopmean[i].foods.length;k++){var isadd=true;                          //判断该商品是否在购物车for( var h=0;h<this.mycar.length;h++){if(this.shopmean[i].foods[k].specfoods[0]._id==this.mycar[h].shop.specfoods[0]._id){this.shopmean[i].foods[k].mynum=this.mycar[h].num;thisnum+=this.mycar[h].num;isadd=false;break;}}if(isadd){this.shopmean[i].foods[k].mynum=0;}}this.shopmean[i].mynum=thisnum;}return this.shopmean}},methods:{//函数imgaddpath:function(e){return "/"+e+".jpeg"},itemgo:function(index){this.shopon=index;document.querySelector('.mainright').scrollTop=document.querySelectorAll('.itemtop')[index].offsetTop;},handleScroll:function(){var mydiv=document.querySelectorAll('.item');for(var i =0;i<mydiv.length;i++){if(mydiv[i].offsetTop>document.querySelector('.mainright').scrollTop-10&&mydiv[i].offsetTop<document.querySelector('.mainright').scrollTop+10){this.shopon=i;   }}},newpage:function(){this.myrouter=(this.$route.path=="/shop"?true:false);this.footdiv=(((this.$route.path=="/shop"&&this.shoporscore)||this.$route.path=="/shop/foodDetail")?true:false);},gofoodDetail:function(){this.$router.push("/shop/foodDetail");},addcar:function(e){var that=this;if(localStorage.getItem("mycar")){var mycar=JSON.parse(localStorage.getItem("mycar"));var addok=true;                                              //数据是否添加for(var i =0;i<mycar.length;i++){if(mycar[i].shop.item_id==e.item_id&&mycar[i].shop.category_id==e.category_id&&mycar[i].shop.restaurant_id==e.restaurant_id){mycar[i].num=mycar[i].num+1;addok=false;break;}}if(addok){mycar.push({"shop":e,"num":1});}that.mycar=mycar;localStorage.setItem("mycar",JSON.stringify(mycar));}else{var mycar=[{"shop":e,"num":1}];that.mycar=mycar;localStorage.setItem("mycar",JSON.stringify(mycar));};},removecar:function(e){for(var i=0;i<this.mycar.length;i++){if(this.mycar[i].shop.specfoods[0]._id==e.specfoods[0]._id){this.mycar[i].num==1?this.mycar.splice(i,1):(this.mycar[i].num=this.mycar[i].num-1);break;}}localStorage.setItem("mycar",JSON.stringify(this.mycar));}},watch:{"$route":"newpage",}
}
</script><!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.big{display:-webkit-box;-webkit-box-orient:vertical;height:100vh;
}.shoptop{height:120px;background-color: rgba(119,103,137,.43);box-sizing:border-box;padding:10px 10px 0px 10px;position: relative;
}
.topbg{position: absolute;width:100%;height:120px;left:0px;right:0px;overflow:hidden;
}
.topbgimg{width:100%;filter: blur(10px);
}
.backicon{height:30px;width:30px;
}
.backicon2{height:25px;width:25px;
}
.toptop{margin-bottom:10px;
}
.topfoot{height:70px;display:flex;
}
.topleft{height:80px;width:80px;background-color:#3c3c3c;margin-right:10px;border-radius:3px;box-shadow:0 0 5px #3c3c3c;  
}
.topleft>img{max-width:100%;max-height:100%;border-radius:3px;
}
.topright,.topleft{float:left;
}
.topright{height:100%;flex:1;
}
.foota{height:30px;color:white;line-height:30px;display:flex;
}
.icon3{width:20px;height:20px;margin-top:5px;
}
.footc{height:20px;line-height:20px;font-size:12px;
}
.footb{font-size:12px;color:white;
}
.footcmain{background-color:#0097FF;color:white;padding:0px 5px; 
}
.shopmid{padding:10px 10px 0px 10px;border-bottom:2px solid #F8F8F8;
}
.midtop{font-size:12px;
}
.te{background-color:#F08449;padding:0px 1px;color:white;
}
.mytab{overflow:hidden;margin-top:10px;
}
.mytab>div{float:left;padding-bottom:10px;margin-right:10px;border-bottom:2px solid white;
}
.mytab>div.on{color:#0B89FF;border-color:#0B89FF;
}
.leftdiv{width:60px;padding:0px 10px;color:#727272;background-color:#F8F8F8;
}
.leftdiv>div{padding:15px 0px;border-bottom:1px solid #F1F1F1;
}
.leftdiv.on{background-color:white;color:#080808;
}
.leftdiv.on>div{border:0px;
}
.icon5{width:15px;height:15px;
}
.mianleft{width:80px;box-sizing:border-box;overflow:scroll;
}
.shopmain{-webkit-box-flex:1;display:-webkit-box;overflow:hidden;margin-bottom:50px;
}
.mainright{-webkit-box-flex:1;overflow:scroll;padding-left:10px;position: relative;
}
.foot{height:50px;line-height:50px;background-color:#594C46;display:flex;position:fixed;bottom:0px;left:0px;width:100%;
}
.foot.on .footicon{color:#fff;
}
.foot.on .footmain{color:#fff;
}
.foot.on .footright{color:#fff;
}
.foot.on .footlogo{background-color:#3190E8;
}
.footleft{flex:2;display:flex;
}
.footright{flex:1;text-align:center;color:#B7B7B7;background-color:#61686A;
}
.footright.on{background-color:#4CD964;color:white;
}
.footlogo{text-align:center;width:50px;height:50px;border-radius:50%;background-color:#515151;margin:0px 10px;border:3px solid #444446;transform:translatey(-15px)
}
.footicon{color:#8a8a8a;width:40px;height:40px;margin-top:7px;
}
.footmain{height:50px;color:#ADADAD;font-size:0.8rem;
}
.itemmain{padding-right:10px;}
.iteminfo{height:70px;display:flex;padding:10px 0px;
}
.infoimgbox{width:70px;height:70px;margin-right:5px;background-color:red;
}
.infoimgbox>img{width:100%;height:100%;
}
.inforight{flex:1;
}
.ih20{height:20px;line-height:20px;
}
.ih15{height:15px;line-height:15px;
}
.addicon{width:20px;height:20px;
}
.zk{background-color:#FF5F15;padding:0px 3px;color:white;border:1px solid #FF5F15;
}
.yh{padding:0px 3px;color:#FF5F15;border:1px solid #FF5F15;
}
.gz{display:inline-block;background-color:#3190E8;color:white;padding:0px 2px;border-radius:2px;
}.scoretop{display:flex;padding:0px 10px 10px 10px;border-bottom:10px solid #F5F5F5;
}
.scoretopleft{flex:2;text-align:center;
}
.scoretopright{flex:3;
}
.scoretopright>div{display:flex;
}
.scoremain{padding:0px 10px;
}
.scoremaintop{padding:10px 0px 5px 0px;display:flex;flex-wrap:wrap;
}
.scoremaintop>div{padding:0px 8px;border-radius:5px;margin-right:5px;margin-bottom:5px;
}
.sty1{background-color:#EBF5FF;color:#9f9f9f;
}
.sty1.on{background-color:#3190E8;color:#fff;
}
.sty2{background-color:#F5F5F5;color:#AFAFAF;
}
.scoreitem{display:flex;margin-top:10px;
}
.scoreitemleft{width:50px;height:50px;margin-right:10px;
}
.scoreitemleft>img{width:100%;border-radius:50%; 
}
.scoreitemright{flex:1;
}
.namebox{display:flex;flex-wrap: wrap;
}
.namebox>div{border:1px solid;padding:3px 3px;margin-right:5px;border-radius:3px;margin-bottom:5px;
}
.score{padding-top:10px;flex:1;overflow-y: scroll;
}
.scoreimgbox>img{width:4rem;height:4rem;margin-right:10px;
}
.modal{box-sizing:border-box;width:100vw;height:100vh;background-color:#262626;position:fixed;top:0px;left:0px;z-index:10;}
.modaltop{overflow: scroll;
}
.modaltitle{margin:20px 0px;text-align:center;font-size:1.5rem;
}
.modal_title{text-align:center;margin:10px;
}
.modal_title>span{padding:2px 5px;border:1px solid #fff;border-radius:5px;
}
.modalfoot{width:100%;margin-bottom:10px;justify-content:flex-end;text-align:center;
}
.modalfoot>span{display: inline-block;border:1px solid #fff;border-radius:50%;width:30px;padding:5px;height:30px;ling-height:30px;font-size:25px;
}
.iteminfofoot{position: absolute;bottom: 10px;right: 0px;
}
.hidden{overflow: hidden;
}
.rednum{position: absolute;top:-3px;right:-5px;border-radius:50%;background-color:red;color:white;height:18px;width:18px;text-align:center;line-height:18px;font-size:12px;
}
.y-4{transform: translateY(-4px);
}
.rednum2{position: absolute;top:0px;right:0px;border-radius:50%;background-color:red;color:white;height:15px;width:15px;text-align:center;line-height:15px;font-size:12px;
}
</style>

引入的全局css如下

body{margin: 0px;height: 100vh;background-color: #f5f5f5;
}*{text-decoration:none;
}
.fixed{position: fixed;top: 0px;width: 100%;z-index: 5;
}.ih40{height: 40px;line-height: 40px;
}
.ih30{height: 30px;line-height: 30px;
}
.ih50{height: 50px;line-height: 50px;
}.bgcol{background-color:#26a2ff;
}
.bgfff{background-color: #fff;
}
.bgf5{background-color:#F5F5F5;
}.fs0-8{font-size: 0.8rem !important;
}
.fs1-2{font-size: 1.2rem;
}
.fs15{font-size: 15px;
}
.fs12{font-size: 12px;
}
.fs10{font-size: 12px;transform: scale(.8);display:inline-block;
}
.mgr{transform-origin:100% 50% 0;/*改变缩放基点*/
}
.mgl{transform-origin:0 50% 0;/*改变缩放基点*/
}
.colfff{color: #fff;
}
.col9f{color: #9F9F9F;
}
.colf60{color: #FF6600;
}
.col{color: #26a2ff;
}
.colred{color:#FE3D3D;
}
.colblack{color: black;
}
.pad10{padding: 10px;
}
.padlr10{padding:0px 10px 0px 10px;
}
.padtop10{padding-top:10px; 
}
.padtop40{padding-top:40px;
}
.padtop50{padding-top:50px;
}
.padbot10{padding-bottom:10px; 
}
.padr10{padding-right: 10px;
}
.mgtop5{margin-top: 5px;
}
.mgtop40{margin-top: 40px;
}
.mgtop50{margin-top: 50px;
}
.mgtop10{margin-top: 10px;
}
.mgbot10{margin-bottom: 10px;
}
.mgr5{margin-right: 5px;
}
.w15{width: 15px;height: 15px;
}
.w60{width: 60px;height: 60px;
}
.w100{width: 100%;
}
.radius50{border-radius: 50%;
}
.inblock{display: inline-block;
}
.flex{display: flex;
}
.flex2{display: flex;flex-direction:column;
}
.flex1{flex: 1;
}
.ovhid{overflow: hidden;
}
.box{box-sizing: border-box;
}
.right{float: right;
}.clear{clear: both;
}
.relative{position: relative;
}
.left{float: left;
}
.midline{text-decoration: line-through;
}
.nowarp{white-space:nowrap;          /* 不换行 */overflow:hidden;               /* 内容超出宽度时隐藏超出部分的内容 */text-overflow:ellipsis;   /* 当对象内文本溢出时显示省略标记(...) ;需与overflow:hidden;一起使用。*/
}
/*一像素分割线*/
.after{position: relative;
}
.after::after{content: " ";position: absolute;left: 0;bottom: 0;width: 100%;height: 1px;background-color: #e4e4e4;-webkit-transform-origin: left bottom;transform-origin: left bottom;
}
/* 2倍屏 */
@media only screen and (-webkit-min-device-pixel-ratio: 2.0) {.after::after {-webkit-transform: scaleY(0.5);transform: scaleY(0.5);}
}/* 3倍屏 */
@media only screen and (-webkit-min-device-pixel-ratio: 3.0) {.after::after {-webkit-transform: scaleY(0.33);transform: scaleY(0.33);}
}/* 组件动画 */
/* 左进左出 */
.left-enter-active{animation-name: left-in;animation-duration: .2s; animation-timing-function:linear;
}
.left-leave-active{animation-name: left-out;animation-timing-function:linear;animation-duration: .2s; 
}
@keyframes left-in {0% {transform: translate3d(-100%, 0, 0);}50% {transform: translate3d(-50%, 0, 0);}100% {transform: translate3d(0, 0, 0);}
}
@keyframes left-out {0% {transform: translate3d(0, 0, 0);}50% {transform: translate3d(-50%, 0, 0);}100% {transform: translate3d(-100%, 0, 0);}
}/* 右进右出 */
.right-enter-active{animation-name: right-in;animation-duration: .2s; animation-timing-function:linear;
}
.right-leave-active{animation-name: right-out;animation-timing-function:linear;animation-duration: .2s; 
}
@keyframes right-in {0% {transform: translate3d(100%, 0, 0);}50% {transform: translate3d(50%, 0, 0);}100% {transform: translate3d(0, 0, 0);}
}
@keyframes right-out {0% {transform: translate3d(0, 0, 0);}50% {transform: translate3d(50%, 0, 0);}100% {transform: translate3d(100%, 0, 0);}
}/* 上进上出 */
.top-enter-active{animation-name: top-in;animation-duration: .2s; animation-timing-function:linear;
}
.top-leave-active{animation-name: top-out;animation-timing-function:linear;animation-duration: .2s; 
}
@keyframes top-in {0% {transform: translate3d(0, -100%, 0);}50% {transform: translate3d(0, -50%, 0);}100% {transform: translate3d(0, 0, 0);}
}
@keyframes top-out {0% {transform: translate3d(0, 0, 0);}50% {transform: translate3d(0, -50%, 0);}100% {transform: translate3d(0, -100%, 0);}
}/* 淡进淡出 */
.opacity-enter-active{animation-name: opacity-in;animation-duration: .2s; animation-timing-function:linear;
}
.opacity-leave-active{animation-name: opacity-out;animation-timing-function:linear;animation-duration: .2s; 
}
@keyframes opacity-in {0% {opacity:0;}50% {opacity:0.5;}100% {opacity:1;}
}
@keyframes opacity-out {0% {opacity:1;}50% {opacity:0.5;}100% {opacity:0;}
}

下面来改造购物车

更多推荐

vue从创建到完整的饿了么(17)本地缓存实现购物车

本文发布于:2024-02-11 11:00:26,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1680631.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:购物车   饿了   缓存   完整   vue

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!