视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Vue商品控件与购物车联动效果的实例代码
2020-11-27 21:53:29 责编:小采
文档


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

商品控件

商品控件的结构编写

 

在商品组件的<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>

购物车组件

 

我们现在创建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: #6158;
}

.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商品控件与购物车联动效果的实例代码,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

下载本文
显示全文
专题