<template>
<div class="cartcontroller">
<transition name="move">
<div class="cart-decrease" v-show="showDecrease" @click="decreaseCart">
<i class="inner icon-remove_circle_outline"></i>
</div>
</transition>
<div class="cart-count" v-show="showDecrease">{{this.food.count}}</div>
<div class="cart-add" @click="addCart">
<i class="icon-add_circle"></i>
</div>
</div>
</template>
<script>
import Vue from "vue";
export default {
name: "CartController",
props: {
food: {
type: Object
}
},
components: {},
data() {
return {};
},
methods: {
addCart(event) {
if (!event._constructed) {
return;
}
if (!this.food.count) {
//查看Vue的文档发现,set可以在全局增加响应式视图需要的属性
Vue.set(this.food, "count", 1);
this.food.count = 1;
} else {
this.food.count += 1;
}
let _target = event.target;
if (!_target.classList.contains("cart-add")) {
_target = event.target.parentNode;
}
this.$emit("cart-add", _target);
},
decreaseCart(event) {
if (!event._constructed) {
return;
}
if (this.food.count) {
this.food.count--;
}
}
},
computed: {
showDecrease: function() {
return this.food.count > 0;
}
}
};
</script>
<style lang="stylus" scoped>
.cartcontroller
font-size: 0
.cart-add
display: inline-block
padding: 6px
line-height: 24px
font-size: 24px
color: rgb(0, 160, 220)
.cart-decrease
display: inline-block
padding: 6px
transition: all 0.5s linear
.inner
display: inline-block
line-height: 24px
font-size: 24px
color: rgb(0, 160, 220)
&.move-leave, &.move-enter-to
opacity: 1
transform: translate3d(0, 0, 0)
.inner
transform: rotate(0)
transition: all 0.5s linear
&.move-enter, &.move-leave-to
opacity: 0
transform: translate3d(48px, 0, 0)
.inner
transform: rotate(360deg)
transition: all 0.5s linear
.cart-count
display: inline-block
vertical-align: top
width: 12px
padding-top: 6px
height: 24px
line-height: 24px
text-align: center
font-size: 10px
color: rgb(147, 153, 159)
</style>
下面是shopcar组件,调用上面的组件
<template>
<div class="shopcart">
<div class="content" @click="toggleList">
<div class="content-left">
<div class="logo-wrapper">
<div class="logo" :class="{'highlight':totalCount>0}">
<i class="icon-shopping_cart" :class="{'highlight':totalCount>0}"></i>
</div>
<div class="num" v-show="totalCount>0">{{totalCount}}</div>
</div>
<div class="price" :class="{'highlight':totalPrice>0}">¥{{totalPrice}}</div>
<div class="desc">另需配送费¥{{seller.deliveryPrice}}元</div>
</div>
<div class="content-right">
<div class="content-minPrice" :class="payClass">{{payDesc}}</div>
</div>
</div>
<div class="ball-container">
<div v-for="(ball,index) in balls" :key="index">
<transition
name="drop"
@before-enter="beforeDrop"
@enter="dropping"
@after-enter="afterDrop"
>
<div class="ball" v-show="ball.show">
<div class="inner inner-hook"></div>
</div>
</transition>
</div>
</div>
<transition name="fold-cart">
<div class="shopcart-list" v-show="listShow">
<div class="list-header">
<h1 class="title">购物车</h1>
<span class="empty">清空</span>
</div>
<div class="list-content" ref="listContent">
<ul>
<li class="food" v-for="(food,index) of selectFoods" :key="index">
<span class="name">{{food.name}}</span>
<div class="price">
<span>¥{{food.price*food.count}}</span>
</div>
<div class="cartcontrol-wrapper">
<cart-controller :food="food"></cart-controller>
</div>
</li>
</ul>
</div>
</div>
</transition>
</div>
</template>
<script>
import CartController from "../cartCtr/cartCtr";
import BScroll from "@better-scroll/core";
export default {
name: "ShopCar",
props: {
seller: {
type: Object
},
selectFoods: {
type: Array,
default() {
return [
{
price: 0,
count: 0
}
];
}
}
},
components: {
CartController
},
data() {
return {
balls: [
{
show: false
},
{
show: false
},
{
show: false
},
{
show: false
},
{
show: false
}
],
dropBalls: [],
listShow: false
};
},
methods: {
drop: function(el) {
for (let index = 0; index < this.balls.length; index++) {
let ball = this.balls[index];
if (!ball.show) {
ball.show = true;
ball.el = el;
this.dropBalls.push(ball);
return;
}
}
},
beforeDrop(el) {
let count = this.balls.length;
while (count--) {
let ball = this.balls[count];
if (ball.show) {
let rect = ball.el.getBoundingClientRect();
let x = rect.left - 32;
let y = -(window.innerHeight - rect.top - 22);
el.style.display = "";
el.style.webkitTransform = `translate3d(0,${y}px,0)`;
el.style.transform = `translate3d(0,${y}px,0)`;
let inner = el.getElementsByClassName("inner-hook")[0];
inner.style.webkitTransform = `translate3d(${x}px,0,0)`;
inner.style.transform = `translate3d(${x}px,0,0)`;
}
}
},
dropping(el, done) {
/* eslint-disable no-unused-vars */
let rf = el.offsetHeight;
this.$nextTick(() => {
el.style.webkitTransform = "translate3d(0,0,0)";
el.style.transform = "translate3d(0,0,0)";
let inner = el.getElementsByClassName("inner-hook")[0];
inner.style.webkitTransform = "translate3d(0,0,0)";
inner.style.transform = "translate3d(0,0,0)";
el.addEventListener("transitionend", done);
});
},
afterDrop(el) {
let ball = this.dropBalls.shift();
if (ball) {
ball.show = false;
el.style.display = "none";
}
},
toggleList() {
if (this.totalCount > 0) {
this.listShow = !this.listShow;
if (this.listShow) {
this._initScrollShopcart();
}
} else {
return;
}
},
_initScrollShopcart() {
this.$nextTick(() => {
this.scroll = new BScroll(this.$refs.listContent, {
click: true,
bounce: false,
scrollbar: false,
preventDefault: false,
tap: true,
mouseWheel: true
});
});
}
},
computed: {
totalPrice: function() {
let total = 0;
this.selectFoods.forEach(food => {
total += food.price * food.count;
});
return total;
},
totalCount: function() {
let count = 0;
this.selectFoods.forEach(food => {
count += food.count;
});
return count;
},
payDesc: function() {
let minusPrice = this.totalPrice - this.seller.minPrice;
if (this.totalPrice === 0) {
return `¥${this.seller.minPrice}起送`;
} else if (minusPrice > 0) {
return "去结算";
} else {
return `还差¥${Math.abs(minusPrice)}起送`;
}
},
payClass: function() {
if (this.totalPrice < this.seller.minPrice) {
return "not-enough";
} else {
return "enough";
}
}
},
watch: {
totalCount: function() {
if (this.totalCount <= 0) {
this.listShow = false;
}
if (this.listShow && this.totalCount) {
this._initScrollShopcart();
}
}
}
};
</script>
<style lang="stylus" scoped>
@import './assets/common/mixin.styl'
.shopcart
position: fixed
left: 0
bottom: 0
width: 100%
height: 48px
z-index: 50
.content
display: flex
height: 100%
background: #141d27
.content-left
flex: 1
.logo-wrapper
display: inline-block
position: relative
top: -10px
margin: 0 12px
padding: 6px
width: 56px
height: 56px
box-sizing: border-box
vertical-align: top
border-radius: 50%
background: #141d27
.logo
height: 100%
width: 100%
border-radius: 50%
background: #2B343C
text-align: center
&.highlight
background: rgb(0, 160, 220)
.icon-shopping_cart
line-height: 44px
font-size: 24px
color: rgba(255, 255, 255, 0.4)
&.highlight
color: #fff
.num
position: absolute
right: 0
top: 0
min-width: 24px
height: 16px
line-height: 16px
border-radius: 16px
background-color: rgb(240, 20, 20)
text-align: center
font-size: 9px
font-weight: 700
color: rgb(255, 255, 255)
box-shadow: 0 4px 8px 0px rgba(0, 0, 0, 0.4)
.price
display: inline-block
vertical-align: top
margin-top: 12px
padding-right: 12px
line-height: 24px
font-size: 16px
color: rgba(255, 255, 255, 0.4)
font-weight: 700
box-sizing: border-box
border-right: 1px solid rgba(255, 255, 255, 0.1)
&.highlight
color: #fff
.desc
display: inline-block
vertical-align: top
margin-top: 12px
padding-left: 12px
font-size: 16px
color: rgba(255, 255, 255, 0.4)
font-weight: 700
line-height: 24px
.content-right
flex: 0 0 105px
width: 105px
background: #2B333B
.content-minPrice
line-height: 48px
height: 48px
text-align: center
font-size: 12px
color: rgba(255, 255, 255, 0.4)
font-weight: 700
&.not-enough
background: #2b333b
&.enough
background-color: #00b43c
color: #fff
.ball-container
.ball
position: fixed
left: 32px
bottom: 22px
z-index: 200
transition: all 0.4s cubic-bezier(0.49, -0.29, 0.75, 0.41)
.inner
width: 16px
height: 16px
border-radius: 50%
background: rgb(0, 160, 220)
transition: all 0.4s linear
.shopcart-list
position: absolute
left: 0
bottom: 48px
z-index: -1
width: 100%
&.fold-cart-enter
transform: translate3d(0, 100%, 0)
&.fold-cart-enter-to
transition: all 0.8s ease-in-out
transform: translate3d(0, 0, 0)
&.fold-cart-leave
transform: translate3d(0, 0, 0)
&.fold-cart-leave-to
transition: all 0.8s ease-in-out
transform: translate3d(0, 100%, 0)
.list-header
height: 40px
line-height: 40px
padding: 0 18px
background-color: #F3F5F7
border-bottom: 1px solid rgba(7, 17, 27, 0.1)
.title
float: left
font-size: 14px
font-weight: 200
color: rgb(7, 17, 27)
.empty
float: right
font-size: 12px
color: rgb(0, 160, 220)
.list-content
padding: 0 18px
max-height: 217px
overflow: hidden
background: #fff
.food
position: relative
padding: 12px 0
box-sizing: border-box
border-1px(rgba(7, 17, 27, 0.1))
.name
line-height: 24px
font-size: 12px
color: rgb(7, 17, 27)
.price
position: absolute
right: 90px
bottom: 12px
line-height: 24px
font-size: 14px
font-weight: 700
color: rgb(240, 20, 20)
.cartcontrol-wrapper
position: absolute
right: 0
bottom: 6px
</style>
this.scroll.refresh()不起作用,就只能每次都初始化自定义的_initScrollShopcart() 方法。
掌握Vue1.0到2.0再到2.5最全版本应用与迭代,打造极致流畅的WebApp
了解课程