Vue商品控件与购物车联动效果的实例代码


Posted in Javascript onJuly 21, 2019

本篇我们将构建商品控件与购物车联动。

商品控件

商品控件的结构编写

Vue商品控件与购物车联动效果的实例代码 

在商品组件的<template>标签内完成项目结构,以及数据,事件的绑定,与判断逻辑的书写。

<template>
 <div class="goods">
  <div class="menu-wrapper" ref="menuScroll">
   <ul>
    <!--专场-->
    <li class="menu-item" :class="{'current':currentIndex===0}" @click="selectMenu(0)">
     <p class="text">
      <img :src="container.tag_icon" v-if="container.tag_icon" class="icon">
      {{container.tag_name}}
     </p>
    </li>
    <li
     class="menu-item"
     v-for="(item,index) in goods"
     :class="{'current':currentIndex===index+1}"
     @click="selectMenu(index+1)"
    >
     <p class="text">
      <img :src="item.icon" v-if="item.icon" class="icon">
      {{item.name}}
     </p>
    </li>
   </ul>
  </div>
  <!-- 右侧商品列表 -->
  <div class="foods-wrapper" ref="foodScroll">
   <!--专场-->
   <ul>
    <li class="container-list food-list-hook">
     <div v-for="item in container.operation_source_list">
      <img :src="item.pic_url">
     </div>
    </li>
    <!-- 具体分类-->
    <li v-for="item in goods" class="food-list food-list-hook">
     <h3 class="title">{{item.name}}</h3>
     <!--具体商品列表-->
     <ul>
      <li v-for="food in item.spus" class="food-item">
       <div class="icon" :style="head_bg(food.picture)"></div>

       <div class="content">
        <h3 class="name">{{food.name}}</h3>
        <p class="desc" v-if="food.description">{{food.description}}</p>
        <div class="extra">
         <span class="saled">{{food.month_saled_content}}</span>
         <span class="praise">{{food.praise_content}}</span>
        </div>
        <img
         class="product"
         :src="food.product_label_picture"
         v-show="food.product_label_picture"
        >
        <p class="price">
         <span class="text">¥{{food.min_price}}</span>
         <span class="unit">/{{food.unit}}</span>
        </p>
       </div>
       <div class="cartcontrol-wrapper">
        <Cartcontrol :food="food"></Cartcontrol>
       </div>
      </li>
     </ul>
    </li>
   </ul>
  </div>
  <Shopcart :poiInfo="poiInfo" :selectFoods="selectFoods"></Shopcart>
 </div>
</template>

Shopcart组件是Goods组件的子组件,在Shopcart组件初始化的时候我们可以传入给其参数poiInfo selectFoods.

请求数据,声明方法与计算属性

<script>
import BScroll from "better-scroll";//滚动组件
import Shopcart from "components/Shopcart/Shopcart";//购物车
import Cartcontrol from "components/Cartcontrol/Cartcontrol";//控制商品数量按钮

export default {
 data() {
  return {
   container: {},
   goods: [],
   poiInfo: {},
   listHeight: [],
   menuScroll: {},
   foodScroll: {},
   scrollY: 0
  };
 },
 components: {
  BScroll,//引入组件
  Shopcart,
  Cartcontrol

 },
 created() {
  this.$axios
   .get("api/goods")
   .then(response => {
    let json = response.data;
    if (json.code === 0) {
     // 重点
     this.container = json.data.container_operation_source;
     this.goods = json.data.food_spu_tags;
     this.poiInfo = json.data.poi_info;
     this.$nextTick(function() {
      this.initScroll();
      // 左右联动
      // 右->左
      // 计算区间
      this.caculateHeight();
     });
    }
   })
   .catch(function(error) {
    // handle error
    console.log(error);
   });
 },
 computed: {
  // 根据右侧判断左侧index
  currentIndex() {
   for (let i = 0; i < this.listHeight.length; i++) {
    let start = this.listHeight[i];
    let end = this.listHeight[i + 1];
    if (this.scrollY >= start && this.scrollY < end) {
     return i;
    }
   }
   return 0;
  },
  selectFoods() {
   let foods = [];
     this.goods.forEach(good => {
     good.spus.forEach(food => {
      if (food.count > 0) {
       foods.push(food);
      }
     }); 
    });
   return foods;
  }
 },
 methods: {
  head_bg(imgName) {
   return "background-image: url(" + imgName + ");";
  },
  initScroll() {
   this.menuScroll = new BScroll(this.$refs.menuScroll, {
    click: true
   });
   this.foodScroll = new BScroll(this.$refs.foodScroll, {
    probeType: 3,
    click: true
   });
   this.foodScroll.on("scroll", pos => {
    this.scrollY = Math.abs(Math.round(pos.y));
   });
  },
  caculateHeight() {
   let foodList = this.$refs.foodScroll.getElementsByClassName(
    "food-list-hook"
   );//获取到dom元素
   let height = 0;
   this.listHeight.push(height);
   for (let i = 0; i < foodList.length; i++) {
    height += foodList[i].clientHeight;
    this.listHeight.push(height);
   }
   // [0, 215, 1343, 2425, 3483, 4330, 5823, 7237, 8022, 8788, 9443]
  },
  selectMenu(index) {
   let foodlist = this.$refs.foodScroll.getElementsByClassName(
    "food-list-hook"
   );
   // 根据下标,滚动到相对应的元素
   let el = foodlist[index];
   // 滚动到对应元素的位置
   this.foodScroll.scrollToElement(el, 100);
  }
 }
};
</script>

定义商品组件的样式

<style scoped>
.goods {
 display: -webkit-box;
 display: -ms-flexbox;
 display: flex;
 position: absolute;
 top: 190px;
 bottom: 51px;
 overflow: hidden;
 width: 100%;
}
.goods .menu-wrapper {
 -webkit-box-flex: 0;
 -ms-flex: 0 0 85px;
 flex: 0 0 85px;
 background: #f4f4f4;
}
.goods .menu-wrapper .menu-item {
 padding: 16px 23px 15px 10px;
 border-bottom: 1px solid #e4e4e4;
 position: relative;
}
.goods .menu-wrapper .menu-item.current {
 background: white;
 font-weight: bold;
 margin-top: -1px;
}
.goods .menu-wrapper .menu-item:first-child.current {
 margin-top: 1px;
}
.goods .menu-wrapper .menu-item .text {
 font-size: 13px;
 color: #333333;
 line-height: 17px;
 vertical-align: middle;
 -webkit-line-clamp: 2;
 display: -webkit-box;
 -webkit-box-orient: vertical;

 overflow: hidden;
}
.goods .menu-wrapper .menu-item .text .icon {
 width: 15px;
 height: 15px;
 vertical-align: middle;
}
.goods .menu-wrapper .menu-item .num {
 position: absolute;
 right: 5px;
 top: 5px;
 width: 13px;
 height: 13px;
 border-radius: 50%;
 color: white;
 background: red;
 text-align: center;
 font-size: 7px;
 line-height: 13px;
}

.goods .foods-wrapper {
 -webkit-box-flex: 1;
 -ms-flex: 1;
 flex: 1;
 /* background: blue; */
}
.goods .foods-wrapper .container-list {
 padding: 11px 11px 0 11px;
 border-bottom: 1px solid #e4e4e4;
}
.goods .foods-wrapper .container-list img {
 width: 100%;
 margin-bottom: 11px;
 border-radius: 5px;
}
.goods .foods-wrapper .food-list {
 padding: 11px;
}
.goods .foods-wrapper .food-list .title {
 height: 13px;
 font-size: 13px;
 background: url(btn_yellow_highlighted@2x.png) no-repeat left center;
 background-size: 2px 10px;
 padding-left: 7px;
 margin-bottom: 12px;
}

.goods .foods-wrapper .food-list .food-item {
 display: flex;
 margin-bottom: 25px;
 position: relative;
}
.goods .foods-wrapper .food-list .food-item .icon {
 flex: 0 0 63px;
 background-position: center;
 background-size: 120% 100%;
 background-repeat: no-repeat;
 margin-right: 11px;
 height: 75px;
}
.goods .foods-wrapper .food-list .food-item .content {
 flex: 1;
}
.goods .foods-wrapper .food-list .food-item .content .name {
 font-size: 16px;
 line-height: 21px;
 color: #333333;
 margin-bottom: 10px;
 padding-right: 27px;
}
.goods .foods-wrapper .food-list .food-item .content .desc {
 font-size: 10px;
 line-height: 19px;
 color: #bfbfbf;
 margin-bottom: 8px;

 /* 超出部分显示省略号*/
 -webkit-line-clamp: 1;
 display: -webkit-box;
 -webkit-box-orient: vertical;
 overflow: hidden;
}
.goods .foods-wrapper .food-list .food-item .content .extra {
 font-size: 10px;
 color: #bfbfbf;
 margin-bottom: 7px;
}
.goods .foods-wrapper .food-list .food-item .content .extra .saled {
 margin-right: 14px;
}
.goods .foods-wrapper .food-list .food-item .content .product {
 height: 15px;
 margin-bottom: 6px;
}
.goods .foods-wrapper .food-list .food-item .content .price {
 font-size: 0;
}
.goods .foods-wrapper .food-list .food-item .content .price .text {
 font-size: 14px;
 color: #fb4e44;
}
.goods .foods-wrapper .food-list .food-item .content .price .unit {
 font-size: 12px;
 color: #bfbfbf;
}
</style>

商品数量控制组件

这里用了vue动画

cart-decrease类为商品数量减少结构。 使用指令v-show控制其显隐。有商品数量的时候会按照规定动画进行显示,反之则隐藏。

cart-count类为选中的商品数量。

cart-add类为商品数量增加结构。

通过vue全局api set进行第一次点击增加商品按钮时候的设置。

https://cn.vuejs.org/v2/api/#...

<template>
 <div class="cartcontrol">
  <transition name="move">
   <div class="cart-decrease" @click="decreaseCart" v-show="food.count">
    <span class="inner icon-remove_circle_outline"></span>
   </div>
  </transition>
  <div class="cart-count" v-show="food.count">{{food.count}}</div>
  <div class="cart-add icon-add_circle" @click="increaseCart">
   <i class="bg"></i>
  </div>
 </div>
</template>

<script>
import Vue from 'vue'
export default {
 props:{
  food:{
   type:Object
  }
 },
 methods:{
  decreaseCart(){
   this.food.count--;
  },
  increaseCart(){
   if(!this.food.count){
    Vue.set(this.food,'count',1);
   }else{
    this.food.count++;
   }
  }
  
 }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.cartcontrol {
 font-size: 0;
}

.cartcontrol .cart-decrease {
 display: inline-block;
 width: 26px;
 height: 26px;
 font-size: 26px;
 color: #b4b4b4;
}

.cartcontrol .cart-count {
 display: inline-block;
 width: 25px;
 text-align: center;
 font-size: 12px;
 line-height: 26px;
 vertical-align: top;
}

.cartcontrol .cart-add {
 display: inline-block;
 width: 26px;
 height: 26px;
 font-size: 26px;
 color: #ffd161;
 position: relative;
}
.cartcontrol .cart-add .bg {
 width: 20px;
 height: 20px;
 border-radius: 50%;
 background: black;
 position: absolute;
 left: 3px;
 top: 3px;
 z-index: -1;
}

.move-enter-active,
.move-leave-active {
 transition: all 0.5s linear;
}
.move-enter,
.move-leave-to {
 transform: translateX(20px) rotate(180deg);
}
</style>

购物车组件

Vue商品控件与购物车联动效果的实例代码 

我们现在创建shopcart购物车组件。

<template>
 <div class="shopcart" :class="{'highligh':totalCount>0}">
  <div class="shopcart-wrapper">
   <div class="content-left">
    <div class="logo-wrapper" :class="{'highligh':totalCount>0}">
     <span class="icon-shopping_cart logo" :class="{'highligh':totalCount>0}"></span>
     <i class="num" v-show="totalCount">{{totalCount}}</i>
    </div>
    <div class="desc-wrapper">
     <p class="total-price" v-show="totalPrice">¥{{totalPrice}}</p>
     <p class="tip" :class="{'highligh':totalCount>0}">另需{{shipping_fee_tip}}</p>
    </div>
   </div>

   <div class="content-right" :class="{'highligh':totalCount>0}">{{payStr}}</div>
  </div>
 </div>
</template>

<script>
// 导入BScroll
import BScroll from "better-scroll";

export default {
 props: {
  min_price_tip: {
   type: String,
   default: ""
  },
  shipping_fee_tip: {
   type: String,
   default: ""
  },
  selectFoods: {
   type: Array,
   default() {
    return [
     /* {
      min_price: 10,
      count: 3
     },
     {
      min_price: 7,
      count: 1
     } */
    ];
   }
  }
 },
 computed: {
  // 总个数 将所选商品的个数累加得到总个数。
  totalCount() {
   let num = 0;
   this.selectFoods.forEach(food => {
    num += food.count;
   });

   return num;
  },
  // 总金额
  totalPrice() {
   let total = 0;
   this.selectFoods.forEach(food => {
    total += food.min_price * food.count;
   });

   return total;
  },
  // 结算按钮显示
  payStr() {
   if (this.totalCount > 0) {
    return "去结算";
   } else {
    return this.min_price_tip;
   }
  }
 },
 components: {
  BScroll
 }
};
</script>

<style>
.shopcart-wrapper {
 width: 100%;
 height: 51px;
 background: #514f4f;
 position: fixed;
 left: 0;
 bottom: 0;
 display: flex;
 z-index: 99;
}
.shopcart-wrapper.highligh {
 background: #2d2b2a;
}

.shopcart-wrapper .content-left {
 flex: 1;
}
.shopcart-wrapper .content-left .logo-wrapper {
 width: 50px;
 height: 50px;
 background: #666666;
 border-radius: 50%;
 position: relative;
 top: -14px;
 left: 10px;
 text-align: center;
 float: left;
}
.shopcart-wrapper .content-left .logo-wrapper.highligh {
 background: #ffd161;
}
.shopcart-wrapper .content-left .logo-wrapper .logo {
 font-size: 28px;
 color: #c4c4c4;
 line-height: 50px;
}
.shopcart-wrapper .content-left .logo-wrapper .logo.highligh {
 color: #2d2b2a;
}
.shopcart-wrapper .content-left .logo-wrapper .num {
 width: 15px;
 height: 15px;
 line-height: 15px;
 border-radius: 50%;
 font-size: 9px;
 color: white;
 background: red;
 position: absolute;
 right: 0;
 top: 0;
}
.shopcart-wrapper .content-left .desc-wrapper {
 float: left;
 margin-left: 13px;
}
.shopcart-wrapper .content-left .desc-wrapper .total-price {
 font-size: 18px;
 line-height: 33px;
 color: white;
}
.shopcart-wrapper .content-left .desc-wrapper .tip {
 font-size: 12px;
 color: #bab9b9;
 line-height: 51px;
}
.shopcart-wrapper .content-left .desc-wrapper .tip.highligh {
 line-height: 12px;
}

.shopcart-wrapper .content-right {
 flex: 0 0 110px;
 font-size: 15px;
 color: #bab9b9;
 line-height: 51px;
 text-align: center;
 font-weight: bold;
}
.shopcart-wrapper .content-right.highligh {
 background: #ffd161;
 color: #2d2b2a;
}

.shopcart-wrapper .shopcart-list {
 position: absolute;
 left: 0;
 top: 0;
 z-index: -1;
 width: 100%;
}
.shopcart-wrapper .shopcart-list.show {
 transform: translateY(-100%);
}

.shopcart-wrapper .shopcart-list .list-top {
 height: 30px;
 text-align: center;
 font-size: 11px;
 background: #f3e6c6;
 line-height: 30px;
 color: #646158;
}

.shopcart-wrapper .shopcart-list .list-header {
 height: 30px;
 background: #f4f4f4;
}
.shopcart-wrapper .shopcart-list .list-header .title {
 float: left;
 border-left: 4px solid #53c123;
 padding-left: 6px;
 line-height: 30px;
 font-size: 12px;
}
.shopcart-wrapper .shopcart-list .list-header .empty {
 float: right;
 line-height: 30px;
 margin-right: 10px;
 font-size: 0;
}
.shopcart-wrapper .shopcart-list .list-header .empty img {
 height: 14px;
 margin-right: 9px;
 vertical-align: middle;
}
.shopcart-wrapper .shopcart-list .list-header .empty span {
 font-size: 12px;
 vertical-align: middle;
}

.shopcart-wrapper .shopcart-list .list-content {
 max-height: 360px;
 overflow: hidden;
 background: white;
}
.shopcart-wrapper .shopcart-list .list-content .food-item {
 height: 38px;
 padding: 12px 12px 10px 12px;
 border-bottom: 1px solid #f4f4f4;
}
.shopcart-wrapper .shopcart-list .list-content .food-item .desc-wrapper {
 float: left;
 width: 240px;
}
.shopcart-wrapper
 .shopcart-list
 .list-content
 .food-item
 .desc-wrapper
 .desc-left {
 float: left;
 width: 170px;
}
.shopcart-wrapper
 .shopcart-list
 .list-content
 .food-item
 .desc-wrapper
 .desc-left
 .name {
 font-size: 16px;
 margin-bottom: 8px;

 /* 超出部分隐藏*/
 -webkit-line-clamp: 1;
 display: -webkit-box;
 -webkit-box-orient: vertical;
 overflow: hidden;
 height: 16px;
}
.shopcart-wrapper
 .shopcart-list
 .list-content
 .food-item
 .desc-wrapper
 .desc-left
 .unit {
 font-size: 12px;
 color: #b4b4b4;
}
.shopcart-wrapper
 .shopcart-list
 .list-content
 .food-item
 .desc-wrapper
 .desc-left
 .description {
 font-size: 12px;
 color: #b4b4b4;

 /* 超出部分隐藏*/
 overflow: hidden;
 height: 12px;
}
.shopcart-wrapper
 .shopcart-list
 .list-content
 .food-item
 .desc-wrapper
 .desc-right {
 float: right;
 width: 70px;
 text-align: right;
}
.shopcart-wrapper
 .shopcart-list
 .list-content
 .food-item
 .desc-wrapper
 .desc-right
 .price {
 font-size: 12px;
 line-height: 38px;
}

.shopcart-wrapper .shopcart-list .list-content .food-item .cartcontrol-wrapper {
 float: right;
 margin-top: 6px;
}

.shopcart .shopcart-mask {
 position: fixed;
 top: 0;
 right: 0;
 width: 100%;
 height: 100%;
 z-index: 98px;
 background: rgba(7, 17, 27, 0.6);
}
</style>

Vue商品控件与购物车联动效果的实例代码 

到此购物车与组件联动就结束了。下篇我们讲如何进行商品分类菜单数量提示。

总结

以上所述是小编给大家介绍的Vue商品控件与购物车联动效果的实例代码,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

Javascript 相关文章推荐
jQuery function的正确书写方法
Aug 02 Javascript
基于javascript实现动态显示当前系统时间
Jan 28 Javascript
【JS+CSS3】实现带预览图幻灯片效果的示例代码
Mar 17 Javascript
JS中静态页面实现微信分享功能
Feb 06 Javascript
Linux使用Node.js建立访问静态网页的服务实例详解
Mar 21 Javascript
使用Bootrap和Vue实现仿百度搜索功能
Oct 26 Javascript
jQuery实现的监听导航滚动置顶状态功能示例
Jul 23 jQuery
layui 实现二级弹窗弹出之后 关闭一级弹窗的方法
Sep 18 Javascript
在layer弹层layer.prompt中,修改placeholder的实现方法
Sep 27 Javascript
搭建vscode+vue环境的详细教程
Aug 31 Javascript
JavaScript实现H5接金币功能(实例代码)
Feb 22 Javascript
Vue的生命周期一起来看看
Feb 24 Vue.js
浅析Angular 实现一个repeat指令的方法
Jul 21 #Javascript
Node.js 实现简单的无侵入式缓存框架的方法
Jul 21 #Javascript
Vue中遍历数组的新方法实例详解
Jul 21 #Javascript
Vue项目中使用WebUploader实现文件上传的方法
Jul 21 #Javascript
jquery插件开发模式实例详解
Jul 20 #jQuery
JS回调函数原理与用法详解【附PHP回调函数】
Jul 20 #Javascript
JavaScript展开操作符(Spread operator)详解
Jul 20 #Javascript
You might like
php格式化工具Beautify PHP小小BUG
2008/04/24 PHP
JavaScript中令你抓狂的魔术变量
2006/11/30 Javascript
javascript 鼠标悬浮图片显示原图 移出鼠标后原图消失(多图)
2009/12/28 Javascript
js监听表单value的修改同步问题,跨浏览器支持
2009/12/31 Javascript
JavaScript日历实现代码
2010/09/12 Javascript
jQuery下的动画处理总结
2013/10/10 Javascript
javascript移动设备Web开发中对touch事件的封装实例
2014/06/05 Javascript
jQuery 动态云标签插件
2014/11/11 Javascript
浅谈Jquery中Ajax异步请求中的async参数的作用
2016/06/06 Javascript
Bootstrap表格制作代码
2017/03/17 Javascript
解决AngualrJS页面刷新导致异常显示问题
2017/04/20 Javascript
Vue.JS项目中5个经典Vuex插件
2017/11/28 Javascript
vue webpack开发访问后台接口全局配置的方法
2018/09/18 Javascript
JS开发常用工具函数(小结)
2019/07/04 Javascript
JavaScript 反射和属性赋值实例解析
2019/10/28 Javascript
用云开发Cloudbase实现小程序多图片内容安全监测的代码详解
2020/06/07 Javascript
[01:27:44]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Aster BO3 第一场 1月24日
2021/03/11 DOTA
Python代码调试的几种方法总结
2015/04/15 Python
Python做简单的字符串匹配详解
2017/03/21 Python
利用python爬取散文网的文章实例教程
2017/06/18 Python
python矩阵的转置和逆转实例
2018/12/12 Python
Python 使用list和tuple+条件判断详解
2019/07/30 Python
CentOS7下安装python3.6.8的教程详解
2020/01/03 Python
Anaconda和ipython环境适配的实现
2020/04/22 Python
Python logging模块原理解析及应用
2020/08/13 Python
Origins悦木之源英国官网:雅诗兰黛集团高端植物护肤品牌
2017/11/06 全球购物
大学生未来职业生涯规划书
2014/02/15 职场文书
美术毕业生求职信
2014/02/25 职场文书
颁奖晚会主持词
2014/03/25 职场文书
厕所文明标语
2014/06/11 职场文书
2014年幼儿园老师工作总结
2014/12/05 职场文书
2014年酒店服务员工作总结
2014/12/08 职场文书
2015个人年度工作总结范文
2015/05/28 职场文书
VS2019连接MySQL数据库的过程及常见问题总结
2021/11/27 MySQL
Redis安装使用RedisJSON模块的方法
2022/03/23 Redis
Oracle查看表空间使用率以及爆满解决方案详解
2022/07/23 Oracle