使用 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'
}
}
複製代碼