底部购物车(美团外卖效果)

冷不防 2021-07-24 14:41 480阅读 0赞
  1. 1、实现列表数据和底部购物车数据共享:
  2. (1)vuexstate添加一个属性,用来存储购物车列表的数据,购物车列表的每一项都是商品对象
  3. (2)当点击增加按钮时,往当前商品对象中添加count数据:
  4. 利用vuex,当点击增加/减少按钮时,将当前物品对象中添加一个count属性,
  5. 因为是对象的引用关系,如果vuex之前的state状态中已经存在商品列表的数据,无需再添加额外的state状态,
  6. 当前对象改变属性(利用Vue.set,将对象的新属性交给vue来动态绑定数据),商品列表中的该元素也会相应改变
  7. 添加count属性后,即可根据加减来改变count属性的值,从而实现获得该商品的数量
  8. (3)vuex创建对应的方法来进行第(2)步
  9. actions.js中创建方法来调用mutations.js内的方法来使得状态增/减,方法的传入当前对象
  10. 调用actions.js:this.$store.dispatch('xx',{对象:xx});
  11. actions.js: xx({commit},{对象})
  12. {
  13. commit(RECEIVE_XXX,{对象});
  14. },
  15. mutations.js:
  16. [RECEIVE_XXX](state,{对象})
  17. {
  18. if(对象.count)
  19. {
  20. food.count++;
  21. }else{
  22. state.购物车列表.push(对象); //增加时往购物车列表添加该商品对象,相同商品只改变了count属性,所以每个商品只需要添加一次
  23. Vue.set(对象,'count',1); //让对象新增的数据能够被vue数据绑定,动态更新
  24. }
  25. }
  26. (4)通过state中的购物车列表的内容,实现底部购物车的数据展示
  27. 因为需要实时更新,且建立在已有数据state
  28. getters.js中定义计算属性方法,通过遍历购物车列表的每一个对象中的count,来计算数量和总价
  29. totalCount(state)
  30. {
  31. return state.购物车列表.reduce((preTotal,food)=>{return preTotal+food.count},0)
  32. },
  33. totalPrice(state)
  34. {
  35. return state.购物车列表.reduce((preTotal,food)=>{return preTotal+food.count*food.price},0)
  36. }
  37. (5)将vuex状态引入到组件,实现对应功能
  38. (6)清除购物车
  39. 遍历购物车列表,将所有对象的count属性值置为0,然后将整个列表置空(=[ ])
  40. 对象的引用:
  41. 多个对象引用同一个对象,其中一个改变,都会改变
  42. 多个对象引用同一个对象,其中一个指向另一个对象,其他对象不变

代码示例:
state.js:

  1. export default{
  2. address:"", //地址
  3. categorys:[],//食品分类
  4. shops:[],//商家
  5. userInfo:{ }, //用户信息
  6. goods:[], //商品列表
  7. ratings:[], //商家评价
  8. info:[] ,//商家信息
  9. cartFoods:[] //购物车中的商品列表
  10. }

actions.js

  1. import {
  2. RECEIVE_ADDRESS,
  3. RECEIVE_CATEGORYS,
  4. RECEIVE_SHOPS,
  5. RECEIVE_USERINFO,
  6. RECEIVE_RESET,
  7. RECEIVE_GOODS,
  8. RECEIVE_RATINGS,
  9. RECEIVE_INFO,
  10. RECEIVE_ADD,
  11. RECEIVE_DELETE
  12. } from './mutation-types'
  13. import axios from 'axios';
  14. export default{
  15. //同步更新food中的count数量,增加
  16. updateFoodCount({ commit},{ food})
  17. {
  18. commit(RECEIVE_ADD,{ food});
  19. },
  20. //同步更新food中的counte数量,减少
  21. updateFoodCountDelete({ commit},{ food})
  22. {
  23. commit(RECEIVE_DELETE,{ food});
  24. }
  25. }

mutations.js:

  1. import {
  2. RECEIVE_ADDRESS,
  3. RECEIVE_CATEGORYS,
  4. RECEIVE_SHOPS,
  5. RECEIVE_USERINFO,
  6. RECEIVE_RESET,
  7. RECEIVE_GOODS,
  8. RECEIVE_RATINGS,
  9. RECEIVE_INFO,
  10. RECEIVE_ADD,
  11. RECEIVE_DELETE
  12. } from './mutation-types'
  13. import Vue from 'vue'
  14. export default{
  15. [RECEIVE_ADD](state,{ food})
  16. {
  17. if(food.count)
  18. {
  19. food.count++;
  20. }else{
  21. state.cartFoods.push(food); //增加时往购物车列表添加该商品对象,相同商品只改变了count属性,所以每个商品只需要添加一次
  22. Vue.set(food,'count',1); //让对象新增的数据能够被vue数据绑定,动态更新
  23. }
  24. },
  25. [RECEIVE_DELETE](state,{ food})
  26. {
  27. if(food.count)
  28. {
  29. food.count--; //对象引用,使得属性值减1
  30. if(food.count==0)
  31. {
  32. state.cartFoods.splice(state.cartFoods.indexOf(food),1);
  33. }
  34. }
  35. }
  36. }

getters.js:

  1. export default{
  2. totalCount(state) //返回数量
  3. {
  4. return state.cartFoods.reduce((preTotal,food)=>{ return preTotal+food.count},0)
  5. },
  6. totalPrice(state)//返回总价
  7. {
  8. return state.cartFoods.reduce((preTotal,food)=>{ return preTotal+food.count*food.price},0)
  9. }
  10. }

页面:

  1. <template>
  2. <div class='bf'>
  3. <transition name='wave'>
  4. <div class='blist' v-show='show'> //展开列表
  5. <div class='b1'>
  6. <span>购物车</span>
  7. <span>清空</span>
  8. </div>
  9. //展开列表,根据购物车列表的状态中是否有数据来渲染
  10. <ul class='b2' v-for='(item,index) in cartFoods' :key='index' >
  11. <li class='b3'>
  12. <span>{ { item.name}}</span>
  13. <div class='b4'>
  14. <span>¥{ { item.price}}</span>
  15. <div class='lz'>
  16. <div class='cir' @click='del(item)'>
  17. -
  18. </div>
  19. <span class='cp'>{ { item.count}}</span>
  20. <div class='cir' @click='add(item)'>
  21. +
  22. </div>
  23. </div>
  24. </div>
  25. </li>
  26. </ul>
  27. </div>
  28. </transition>
  29. <div class='bs'>
  30. <div class='bl'>
  31. <div class='bimg' @click='change'>
  32. <img src="./imgs/1.png" alt="">
  33. </div>
  34. <div class='binfo'>
  35. <p>¥{ { totalPrice}}元</p> //根据vuex的计算属性返回总价
  36. <p>另需配送费¥{ { info.deliveryPrice}}元</p>
  37. </div>
  38. </div>
  39. <div class='br' :class='{on:totalPrice>=info.minPrice}'>//根据vuex的计算属性计算价钱
  40. { { totalPrice?totalPrice>=info.minPrice?'去结算':'还差'+(info.minPrice-totalPrice)+'元起送':`¥${ info.minPrice}元起送`}}
  41. </div>
  42. <!-- 购物车图标上的数量提示,根据vuex的购物车列表是否有值显示 -->
  43. <div class='balert' v-show='totalCount'>
  44. { { totalCount}}
  45. </div>
  46. </div>
  47. </div>
  48. </template>
  49. <script>
  50. import { mapState,mapGetters} from 'vuex';
  51. export default {
  52. data()
  53. {
  54. return{
  55. show:false
  56. }
  57. },
  58. methods: {
  59. change() {
  60. this.show=!this.show;
  61. },
  62. del(food) //减少count
  63. {
  64. this.$store.dispatch('updateFoodCountDelete',{ food})
  65. },
  66. add(food) //增加count
  67. {
  68. this.$store.dispatch('updateFoodCount',{ food})
  69. }
  70. },
  71. computed: {
  72. ...mapState(['cartFoods','info']),
  73. ...mapGetters(['totalCount','totalPrice'])
  74. }
  75. }
  76. </script>
  77. <style lang='less'>
  78. .on{
  79. background-color: #44BB00!important;
  80. }
  81. .bf{
  82. width: 100%;
  83. position: fixed;
  84. bottom: 0px;
  85. .blist{
  86. background-color:#F3F5F7;
  87. .b1{
  88. display: flex;
  89. justify-content: space-between;
  90. padding: 0 20px;
  91. height: 40px;
  92. line-height: 40px;
  93. border: solid 1px #ccc;
  94. span:last-child{
  95. padding: 0 10px;
  96. border-left: solid 1px #ccc;
  97. border-right: solid 1px #ccc;
  98. }
  99. }
  100. .b2{
  101. padding-bottom: 10px;
  102. background-color: white;
  103. .b3{
  104. height: 30px;
  105. line-height: 30px;
  106. border-bottom:solid 1px #ccc;
  107. padding:0 20px ;
  108. display: flex;
  109. justify-content: space-between;
  110. .b4{
  111. display: flex;
  112. >span{
  113. color:red
  114. }
  115. .lz{
  116. display: flex;
  117. width: 70px;
  118. justify-content: space-evenly;
  119. align-items: center;
  120. .cir{
  121. text-align: center;
  122. line-height: 20px;
  123. width: 20px;
  124. height: 20px;
  125. color: white;
  126. background-color: #008000;
  127. border-radius: 100px;
  128. }
  129. .cp{
  130. font-size: 10px;
  131. }
  132. }
  133. }
  134. }
  135. }
  136. }
  137. .bs{
  138. color: white;
  139. background-color: #131D29;
  140. height: 50px;
  141. width: 100%;
  142. display: flex;
  143. justify-content: space-between;
  144. position: relative;
  145. .bl{
  146. display: flex;
  147. .bimg{
  148. height: 45px;
  149. width: 45px;
  150. border-radius: 100px;
  151. margin-top: -10px;
  152. background-color: #131D29;
  153. text-align: center;
  154. font-size: 0px;
  155. line-height: 45px;
  156. margin-left: 20px;
  157. img{
  158. height: 40px;
  159. width: 40px;
  160. vertical-align: middle;
  161. }
  162. }
  163. .binfo{
  164. display: flex;
  165. flex-direction: column;
  166. justify-content: space-around;
  167. margin-left: 10px;
  168. p:last-child{
  169. color:#ccc;
  170. font-size: 12px;
  171. }
  172. }
  173. }
  174. .br{
  175. height: 50px;
  176. line-height: 50px;
  177. background-color: #2B333D;
  178. padding:0 10px;
  179. color: white;
  180. }
  181. .balert{
  182. background-color: red;
  183. height: 20px;
  184. width: 20px;
  185. line-height: 20px;
  186. border-radius: 100px;
  187. text-align: center;
  188. position: absolute;
  189. left: 45px;
  190. top:-10px;
  191. }
  192. }
  193. }
  194. .wave-enter-to,.wave-leave{
  195. transform:translateY(0)
  196. }
  197. .wave-enter,.wave-leave-to{
  198. transform:translateY(100%)
  199. }
  200. .wave-enter-active,.wave-leave-active{
  201. transition: transform 1s;
  202. }
  203. </style>

效果图:
在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,480人围观)

还没有评论,来说两句吧...

相关阅读

    相关 详解订单分配内部机制

    公司做外卖配送,正好又在做系统派单这块,遇到很多很多的难点,某日看到了这篇文章,从理论的角度介绍了订单内部分派机制。所以给抄了过来! > 美团点评日前完成最新一轮融资,估值达