1.上一章--watch监听子路由
2.苍渡大神源码--项目源码地址
3.数据接口--API接口
4.UI框架--Mint UI
5.下一章--购物车的详细信息展现与删除css
1.先看一下目前的UI图vue
要实现的UI图node
2.footdiv
代码修改以下git
<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以下github
.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
加一个on
class就行。web
3.点击添加
注意,首先咱们要把布局修改一下segmentfault
之前绿色的div在红色的div内,而红色div有一个点击跳转的效果,因此点击绿色div也会跳转。这在js中解决很是简单,可是在vue中怎么解决呢?我上网查了查没找到结果(哪位老铁知道怎么解决感谢指出)。。。最后是用布局解决的。
解决后红色div与绿色div是兄弟并非父子,将绿色div定位到红色div上便可。框架
4.数据类型
我们把数据存到localStorage
里,键名为mycar
,键值结构为dom
[{"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
来控制on
class是否添加和右上角的红色数字是否显示。
<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(scorerating.compare_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:'http://cangdu.org:8001/img/', //商家头像的路径地址path shopinfo:"", //商家信息 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('http://cangdu.org: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('http://cangdu.org: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('http://cangdu.org: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('http://cangdu.org: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('http://cangdu.org: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 "https://fuss10.elemecdn.com/"+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; } }
下面来改造购物车