共计 7182 个字符,预计需要花费 18 分钟才能阅读完成。
上次我们为商品分类菜单添加了显示购物数量,这篇我们继续推进项目,来实现购物车的详情页面,在开始之前我们先看它在页面中的样子:
如上所示,此页面包含了购物列表,而它由商品名称,单价,增减商品功能构成,增减商品功能我们在商品列表中实现过,那么我们现在可以进行复用。
搭出购物车结构
我们将购物车底部构建出来,
<templete> | |
<div class="shopcart" :class="{'highligh':totalCount>0}"> | |
<div class="shopcart-wrapper"> | |
</div> | |
</div> | |
</templete> |
老情况,在 templete 模板下的 shopcart-wrapper 内完成底部购物车一栏:
1 count 大于 0. 让它打开
<!-- 左 => 内容包含购物车 icon 金额 配送费 --> | |
<div class="content-left"> | |
<div class="logo-wrapper" :class="{'highligh':totalCount>0}" @click="toggleList"> | |
<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}"> 另需 {{poiInfo.shipping_fee_tip}}</p> | |
</div> | |
</div> | |
<!-- 去结算 --> | |
<div class="content-right" :class="{'highligh':totalCount>0}"> | |
{{payStr}} | |
</div> |
搭建所选商品列表
如图所示,我们分好结构,紧接着搭建所选商品的列表
所选商品的列表 shopcart-list 默认隐藏的,也就是说我们在没有选择食品的时候,点击购物车它不会展开。
1.list-hearder,左右结构包括 1 号口袋与清空购物车 | |
2.list-content 列表,存放我们选择的食物 | |
2.1 左边是我们的食物名字,商品描述;右侧是数量,加减商品的组件。<div class="shopcart-list" v-show="listShow" :class="{'show':listShow}"> | |
<!-- 列表顶部满减信息 --> | |
<div class="list-top" v-if="poiInfo.discounts2"> | |
{{poiInfo.discounts2[0].info}} | |
</div> | |
<!-- 1 号口袋 清空功能 --> | |
<div class="list-header"> | |
<h3 class="title">1 号口袋 </h3> | |
<div class="empty" @click="emptyFn"> | |
<img src="./ash_bin.png" /> | |
<span> 清空购物车 </span> | |
</div> | |
</div> | |
<!-- 所选商品列表 --> | |
<div class="list-content" ref='listContent'> | |
<ul> | |
<li class="food-item" v-for="food in selectFoods"> | |
<div class="desc-wrapper"> | |
<!-- 左侧 --> | |
<div class="desc-left"> | |
<!-- 所选商品名字 --> | |
<p class="name">{{food.name}}</p> | |
<!-- 所选商品描述 unit 例 des 霆锋苦辣鸡腿堡 1 个 --> | |
<p class="unit" v-show="!food.description">{{food.unit}}</p> | |
<p class="description" v-show="food.description">{{food.description}}</p> | |
</div> | |
<!-- 商品单价 --> | |
<div class="desc-right"> | |
<span class="price">¥{{food.min_price}}</span> | |
</div> | |
</div> | |
<!-- 复用商品增减组件 Cartcontrol--> | |
<div class="cartcontrol-wrapper"> | |
<Cartcontrol :food='food'></Cartcontrol> | |
</div> | |
</li> | |
</ul> | |
</div> | |
<div class="list-bottom"></div> | |
</div> |
加入遮罩层
<!-- 遮罩层 --> | |
<div class="shopcart-mask" v-show="listShow" @click="hideMask()"></div> | |
到这里,结构咱们就搭好了。
注册组件,添加功能
我们通过 props 为购物车组件传入所需要的数据;
计算属性:
通过 totalCount 计算所选的商品数量;
通过 totalPrice 计算所选商品的总价;
通过 payStr 控制去结算;
listShow 是我们控制购物车详情页展示的要点,依据 totalCount 所选商品数量对 fold 折叠进行控制,fold 为 true,商品数量为 0. 购物车详情页为折叠状态。
接着我们将状态取反赋值到 show,并且依据 show,来控制商品详情页面商品一定多时,可以进行鼠标滚动。
方法:
通过 toggleList 点击购物车 logo 时候,进行判断,如果没有选择商品那么我们什么也不做。如果我们选择了商品,那么将 fold 取反。因为我们在计算属性 listShow 中设置过实例中的 fold 属性为 true,所有它是折叠的。在我们取反后,它就会展开。
emptyFn 清空购物车
最后我们点击遮罩层的时候,让遮罩层隐藏,也就是 fold 为 true。
<script> | |
// 导入 BScroll | |
import BScroll from 'better-scroll' | |
// 导入 Cartcontrol | |
import Cartcontrol from 'components/Cartcontrol/Cartcontrol' | |
export default {data() { | |
return {fold: true} | |
}, | |
props: { | |
poiInfo: { | |
type: Object, | |
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.poiInfo.min_price_tip;} | |
}, | |
listShow() {if(!this.totalCount) { // 个数为 0 | |
this.fold = true; | |
return false; | |
} | |
let show = !this.fold; | |
// BScoll 相关 | |
if(show) {this.$nextTick(() => {if(!this.shopScroll) { | |
this.shopScroll = new BScroll(this.$refs.listContent, {click: true}); | |
} else {this.shopScroll.refresh(); | |
} | |
}); | |
} | |
return show; | |
} | |
}, | |
methods: {toggleList() {if(!this.totalCount) { // 个数为 0 | |
return; | |
} | |
this.fold = !this.fold; | |
}, | |
emptyFn() {this.selectFoods.forEach((food) => {food.count = 0;}); | |
}, | |
hideMask() {this.fold = true;} | |
}, | |
components: { | |
Cartcontrol, | |
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: 98; | |
background: rgba(7,17,27,0.6); | |
} | |
</style> | |
总结
我们从搭购物车结构,到所选商品列表细化,这里我们复用了增减商品的组件,然后加入遮罩层。通过计算属性与方法,加入控制逻辑完成了购物车的详情页面。
下一篇我们来实现商品的详情页面,下周我们不见不散。