使用 ScrollNav组件 url:didi.github.io/cube-ui/#/z…
在tab切换的时候已经将数据的加载处理完成,直接将样式和结构复制到组件当中就能够加载成功vue
<div class="goods">
<div class="scroll-nav-wrapper">
<cube-scroll-nav :side="true" :data="goods" :options="scrollOptions" v-if="goods.length">
<cube-scroll-nav-panel
v-for="good in goods"
:key="good.name"
:label="good.name"
:title="good.name"
>
<ul>
<li v-for="food in good.foods" :key="food.item" class="food-item">
<div class="icon">
<img :src="food.icon" width="57" height="57" />
</div>
<div class="content">
<h2 class="name">{{food.name}}</h2>
</div>
</li>
</ul>
</cube-scroll-nav-panel>
</cube-scroll-nav>
</div>
</div>
复制代码
//完成的goods组件结构
<template>
<div class="goods">
<div class="scroll-nav-wrapper">
<cube-scroll-nav :side="true" :data="goods" :options="scrollOptions" v-if="goods.length">
<cube-scroll-nav-panel
v-for="good in goods"
:key="good.name"
:label="good.name"
:title="good.name"
>
<ul>
<li v-for="food in good.foods" :key="food.item" class="food-item">
<div class="icon">
<img :src="food.icon" width="57" height="57" />
</div>
<div class="content">
<h2 class="name">{{food.name}}</h2>
</div>
</li>
</ul>
</cube-scroll-nav-panel>
</cube-scroll-nav>
</div>
<div class="shop-cart-wrapper">
<!--购物车组件 delivery-pricep配送费 min-price=最低消费-->
<shopCart ref="shopCart" :delivery-price="seller.deliveryPrice" :min-price="seller.minPrice"
></shopCart>
</div>
</div>
</template>
复制代码
js部分的处理git
<script>
import { goodsAjax } from "api/";
import shopCart from "../shop-cart/shop-cart";
export default {
name: "goods",
components: {
shopCart
},
props: {
tabData: {
//动态组件传递过来的值 经过tabs传递过来的值中,都是seller不一次性把全部的数据都加载
type: Object,
default() {
return {};
}
}
},
data() {
return {
goods: [],
selectedFood: {},
scrollOptions: {
click: false, //不监听点击事件,不影响左右滑动又不影响点击时触发滑动
directionLockThreshold: 0
}
};
},
computed: {
seller() {
return this.tabData.seller;
}
},
methods: {
async fetch() {
//打一个标记若是请求过一次数据就再也不进行第二次数据请求,确保组件再来回切换的时候只有一次数据加载
if (this.fetched) return;
this.fetched = true;
this.goods = (await goodsAjax()).data;
}
}
};
</script>
复制代码
购物车样式结构github
<template>
<div>
<div class="shopcart">
<div class="content">
<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">
</div>
</div>
<div class="price" :class="{'highlight':totalPrice>0}">¥{{totalPrice}}</div>
<div class="desc">另需配送费¥{{deliveryPrice}}元</div>
</div>
<div class="content-right">
<div class="pay" :class="payClass">{{payDesc}}</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "shop-cart",
props: {
deliveryPrice: {
type: Number,
default: 0
},
minPrice: {
type: Number,
default: 0
},
selectedFoods: {
type: Array,
default() {
return [];
}
}
},
computed: {
totalPrice() {
//计算总价
let total = 0;
this.selectedFoods.forEach(food => {
total += food.price * food.count;
});
return total;
},
totalCount() {
//计算总和
let count = 0;
this.selectedFoods.forEach(food => {
count += food.count;
});
return count;
},
payDesc() {
//支出的描述
if (this.totalPrice === 0) {
return `¥${this.minPrice}元起送`;
} else if (this.totalPrice < this.minPrice) {
let diff = this.minPrice - this.totalPrice;
return `还差¥${diff}元起送`;
} else {
return "去结算";
}
},
payClass() {
//结算按钮根据不一样的状态,不一样的样式
if (!this.totalCount || this.totalPrice < this.minPrice) {
return "not-enough";
} else {
return "enough";
}
}
}
</script>
复制代码
上面的代码能够正常的显示完整商品列表页面,没有相关的数据处理web
<template>
<div class="cartcontrol">
<transition name="move">
<div class="cart-decrease" v-show="food.count>0" @click.stop="decrease">
<span class="inner icon-remove_circle_outline"></span>
</div>
</transition>
<div class="cart-count" v-show="food.count>0">{{food.count}}</div>
<div class="cart-add icon-add_circle" @click.stop="add"></div>
</div>
</template>
复制代码
js部分的内容:api
<script>
const EVENT_ADD = 'add'
export default {
name: 'cart-control',
props: {
food: { //从goods组件传过来的值
type: Object
}
},
methods: {
add(event) {
if (!this.food.count) {
this.$set(this.food, 'count', 1)
} else {
this.food.count++
}
this.$emit(EVENT_ADD, event.target)
},
decrease() {
if (this.food.count) {
this.food.count--
}
}
}
}
</script>
复制代码
将小球组件引入goods组件中:bash
<template>
<div class="goods">
<div class="scroll-nav-wrapper">
<cube-scroll-nav :side="true" :data="goods" :options="scrollOptions" v-if="goods.length">
<cube-scroll-nav-panel
v-for="good in goods"
:key="good.name"
:label="good.name"
:title="good.name"
>
<ul>
<li
@click="selectFood(food)"
v-for="food in good.foods"
:key="food.name"
class="food-item"
>
<div class="icon">
<img width="57" height="57" :src="food.icon">
</div>
<div class="content">
<h2 class="name">{{food.name}}</h2>
<p class="desc">{{food.description}}</p>
<div class="extra">
<span class="count">月售{{food.sellCount}}份</span><span>好评率{{food.rating}}%</span>
</div>
<div class="price">
<span class="now">¥{{food.price}}</span>
<span class="old" v-show="food.oldPrice">¥{{food.oldPrice}}</span>
</div>
<div class="cart-control-wrapper">
<!--引入 添加减小商品组件 -->
<cart-control @add="onAdd" :food="food"></cart-control>
</div>
</div>
</li>
</ul>
</cube-scroll-nav-panel>
</cube-scroll-nav>
</div>
<div class="shop-cart-wrapper">
<shopCart ref="shopCart" :delivery-price="seller.deliveryPrice" :min-price="seller.minPrice"
:selectedFoods="selectedFoods"
></shopCart>
</div>
</div>
</template>
<script>
import { goodsAjax } from "api/";
import shopCart from "../shop-cart/shop-cart";
import cartControl from "../cart-control/cart-control"
export default {
name: "goods",
components: {
shopCart,
cartControl
},
props: {
tabData: {
//动态组件传递过来的值
type: Object,
default() {
return {};
}
}
},
data() {
return {
goods: [],
selectedFood: {},
scrollOptions: {
click: false, //不监听点击事件,不影响左右滑动又不影响点击时触发滑动
directionLockThreshold: 0
}
};
},
computed: {
seller() {
return this.tabData.seller;
},
selectedFoods(){ //选择商品
let foods = []
this.goods.forEach((good) => {
good.foods.forEach((food) => {
if (food.count) {
foods.push(food)
}
})
})
return foods
}
},
methods: {
async fetch() {
//打一个标记若是请求过一次数据就再也不进行第二次数据请求,确保组件再来回切换的时候只有一次数据加载
if (this.fetched) return;
this.fetched = true;
this.goods = (await goodsAjax()).data;
},
onAdd(){
}
}
};
</script>
<style scoped lang="stylus">
@import "./goods.styl"
</style>
复制代码
小球的动画效果的实现app
1/ 在cart-control.vue组件中,派发一个事件async
<div class="cart-add icon-add_circle" @click.stop="add"></div>
js部分
add(event) {
if (!this.food.count) {
this.$set(this.food, 'count', 1)
} else {
this.food.count++
}
//派发一个事件 在goods子组件当中监听这个事件
this.$emit(EVENT_ADD, event.target)
}
复制代码
2/ 在goods组件当中监听add这个事件ide
<cart-control @add="onAdd :food="food"></cart-control> <script> methods:{ onAdd(el){ //驱动shop-cart组件中 的drop方法 this.$refs.shopCart.drop(el) } } </script> 复制代码
3/ 在shop-cart组件中接收一个参数fetch
methods: {
drop(el){ //驱动的动画
console.log(el)
}
}
复制代码
以上这三步只是找到对应的按钮
4/ shop-cart 建立隐藏的小球
const BALL_LEN = 10;
function createBalls(){//建立隐藏的小球
let ret = [];
for(let i=0;i<BALL_LEN;i++){
ret.push({
show:false
})
}
return ret
}
export default {
data(){
return {
balls:createBalls() //一开始是隐藏的
}
},
}
复制代码
5/ shop-cart 中建立小求容器
<div class="ball-container">
<!-- 小球的容器 -->
<div v-for="(ball,index) in balls" :key="index">
<transition
@before-enter="beforeDrop"
@enter="dropping"
@after-enter="afterDrop ">
<!--第一个元素是v-if v-show 进行过渡的-->
<div class="ball" v-show="ball.show">
<div class="inner inner-hook"></div>
</div>
</transition>
</div>
</div>
复制代码
6/ drop方法触发小球过渡
created(){
this.dropBalls = [];//这是下落小球
},
methods: {
drop(el){ //驱动的动画 小球过渡 找一个小球
for(let i=0;i<this.balls.length;i++) {
const ball = this.balls[i];
if(!ball.show) {
ball.show =true;
ball.el = el;
this.dropBalls.push(ball);//将隐藏小球装到下落小球里面
return
}
}
}
}
复制代码
7/ 小球过渡动画
beforeDrop(el) {
const ball = this.dropBalls[this.dropBalls.length - 1]
//getBoundingClientRect 获取当前元素坐标信息,原生js的语法
const rect = ball.el.getBoundingClientRect()
const x = rect.left - 32
const y = -(window.innerHeight - rect.top - 22)
el.style.display = ''
el.style.transform = el.style.webkitTransform = `translate3d(0,${y}px,0)`
const inner = el.getElementsByClassName(innerClsHook)[0]
inner.style.transform = inner.style.webkitTransform = `translate3d(${x}px,0,0)`
},
dropping(el, done) {
//从新获取元素的位置信息
this._reflow = document.body.offsetHeight
el.style.transform = el.style.webkitTransform = `translate3d(0,0,0)`
const inner = el.getElementsByClassName(innerClsHook)[0]
inner.style.transform = inner.style.webkitTransform = `translate3d(0,0,0)`
el.addEventListener('transitionend', done)
},
afterDrop(el) {
//从动画队列里,将动画的元素去掉
const ball = this.dropBalls.shift()
if (ball) {
ball.show = false
el.style.display = 'none'
}
}
复制代码