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

说明

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

开始

1.先看一下目前的UI图

要实现的UI图

2.footdiv代码修改如下


     
未选购商品
¥ 3205
配送费 ¥5
¥20起送 还差¥15起送 去结算

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

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


          
未选购商品
¥ 3205
配送费 ¥5
¥20起送 还差¥15起送 去结算

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

computed:{
  //计算属性
      mycarshopnum:function(){
          var num=0;
          for(var i=0;i

footdiv中的rednum调用

{{mycarshopnum}}

ok!运行试试

解决!

修改

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

 computed:{
  //计算属性
      //计算商品数量
      mycarshopnum:function(){
          var num=0;
          for(var i=0;i=this.shopinfo.float_minimum_order_amount){
                        return 1
                    }else{
                        return 2
                    }
              }else{
                  return false
              }
      }
  },

footdiv修改如下


          
未选购商品
¥ {{mycarshoppic}}
{{this.shopinfo.piecewise_agent_fee.tips}}
¥{{this.shopinfo.float_minimum_order_amount}}起送 还差¥{{this.shopinfo.float_minimum_order_amount-mycarshoppic}}起送 去结算

运行试试

商品数量

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


    
            
            15
    
 

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

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

 //商品与购物车数量结合
      getshopnum:function(){
          for(var i=0;i

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

v-for="item in shopmean"

改成

v-for="item in getshopnum"

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


      
             
             {{items.mynum}}
      

运行试试

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

删除商品

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


     
         
         {{items.mynum}}
     

methods中写函数

removecar:function(e){
          for(var i=0;i

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

//商品与购物车数量结合
      getshopnum:function(){
          for(var i=0;i

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


          
未选购商品
¥ {{mycarshoppic}}
{{this.shopinfo.piecewise_agent_fee.tips}}
¥{{this.shopinfo.float_minimum_order_amount}}起送 还差¥{{this.shopinfo.float_minimum_order_amount-mycarshoppic}}起送 去结算

运行试试

商品分类小红点

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

//商品与购物车数量结合
      getshopnum:function(){
          for(var i=0;i

结果如下

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

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

最终shop.vue代码修改如下







引入的全局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.js,localstorage)