组件数据(部分):
selectFood是个对象 里面存储的selectFood.餐馆id.食物id = true/false 表示该餐馆中的该食物是否被选中
selectFood.餐馆id.totalPrice 表示该餐馆中食物的总价格
selectFood.餐馆id.allSelect = true/false 表示该餐馆中的所有食物是否被全部选中
deleteSelectFood是个对象 里面存储的deleteSelectFood.餐馆id.食物id = true/false 表示该餐馆中的该食物是否被选中删除
deleteSelectFood.餐馆id.allSelect = true/false 表示该餐馆中的所有食物是否被全部选中删除
组件一创建 查看vuex中的cartList是否有数据(是否为空) 为空代表购物车里面没有东西 并将结果保存在emptyCart变量中
created() {
this.emptyCart = !Object.keys(this.cartList).length
/*cartList是个对象 对象里面的键是restaurant_id 值也是个对象 restaurant_id中保存的是该商店中加入购物车的食品*/
Object.keys(this.cartList).forEach(restaurant_id => {
// 初始化数据
this.selectFood[restaurant_id] = {// 初始化选中列表
allSelect: true,
totalPrice: 0
};
this.deleteSelectFood[restaurant_id] = {// 初始化删除列表
allSelect: false
}
let restaurant = this.cartList[restaurant_id];
Object.keys(restaurant).forEach(data => {
if (Number(data)) {
this.deleteSelectFood[restaurant_id][data] = false;
this.selectFood[restaurant_id][data] = true;
this.selectFood[restaurant_id]['totalPrice'] += Number(restaurant[data]['price']) * Number(restaurant[data]['num']);
}
})
});
}
顶部导航条:复用head组件
复用head组件 右上角插槽展示编辑/取消 通过editStatus变量控制展示哪一个 点击后通过改变editStatus变量来切换展示
<v-head title="购物车" goBack="true" bgColor="#f4f4f4">
<!--editStatus为false 展示这个组件-->
<span slot="edit-cart" class="edit" @click="editStatus = true;" v-if="!editStatus">编辑</span>
<!--editStatus为true 展示这个组件-->
<span slot="cancel-edit-cart" class="edit" @click="editStatus = false;" v-else>取消</span>
</v-head>
购物车为空
如果emptyCart为true 代表购物车为空 展示一个图片 一行字 一个router-link
包裹的文字 点击后跳转到首页
<div class="empty-cart" v-if="emptyCart">
<div class="info-container">
<img src="../../assets/nothing.png">
<span class="text">购物车空空如也,快去逛逛吧</span>
<router-link class="redirect-index" to="/index"><span>去逛逛</span></router-link>
</div>
</div>
商店
- 在非编辑状态下(editStatus为false)也就是我们一进入购物车组件时 所有商品被选中(
selectFood[restaurant_id]['allSelect'] = true
) 展示√这个iconfont 并将所有商品加入allSelect
<span
class="selected"
v-if="!editStatus && selectFood[restaurant_id]['allSelect'] === true"
@click="allSelect(restaurant_id,false)">
<i class="iconfont"></i>
</span>
<span
class="select"
v-else-if="!editStatus"
@click="allSelect(restaurant_id,true)">
</span>
<!--展示餐馆的照片 item是从cartList中遍历出来的商店信息-->
<span class="restaurant-picture">
<img :src="item.pic_url">
</span>
<!--展示餐馆的名称-->
<span class="restaurant-name">{{item.restaurant_name}}</span>
- 在编辑状态下(editStatus为true) 展示“取消”及下面页面 此时这个小圆圈是一个空白小圆圈
点击它后会全部选中该商店下所有商品 此时将这些商品在deleteSelectFood中的标志位全设为true 将deleteSelectFood中的全部选中删除标志位allSelect设为true 展示√这个iconfont
<!--
editStatus为true(在编辑状态下) 并且如果全部选中删除标志位为true 表示该商店下所有商品都被选中
此时商店旁边的那个圈需要选中 只有在这种情况下 商店旁边的那个圈才需要选中
-->
<span
class="delete-selected selected"
v-if="editStatus && deleteSelectFood[restaurant_id]['allSelect'] === true"
@click="allSelectDelete(restaurant_id,false)">
<i class="iconfont"></i>
</span>
<!--editStatus为true 在编辑状态下 就展示个空白的圈-->
<span
class="select"
v-else-if="editStatus"
@click="allSelectDelete(restaurant_id,true)">
</span>
<script>
allSelectDelete(restaurant_id, boolean) { //删除状态下的全选
this.deleteSelectFood[restaurant_id]['allSelect'] = boolean;// 设置全选删除标识符
//将deleteSelectFood中该商店的所有食物都变为true 表示他们选中删除
Object.keys(this.deleteSelectFood[restaurant_id]).forEach(el => {
if (Number(el))
this.deleteSelectFood[restaurant_id][el] = boolean;
})
this.deleteSelectFood = {...this.deleteSelectFood}; //拓展运算符使vue更新视图
},
</script>
删除组件
在编辑状态下(editStatus为true) 展示底部删除
<footer class="btn-delete" v-show="editStatus" @click="deleteCart()">
<span>删除</span>
</footer>
点击底部删除后遍历deleteSelectFood中的restaurant_id 根据restaurant_id遍历food_id 若deleteSelectFood.餐馆id.食物id = true
表示该餐馆中的该食物被选中 要删除 调用vuex中的deleteFood方法 删除vuex中购物车中该餐馆的食品 删除selectFood、deleteSelectFood中该餐馆的指定食品 删除之后展示下面的页面 页面所有商品全部不选中 所以调用allSelect重置
deleteSelectFood.餐馆id.食物id = true/false 表示该餐馆中的该食物是否被选中删除
deleteSelectFood.餐馆id.allSelect = true/false 表示该餐馆中的所有食物是否被全部选中删除
deleteCart() {//删除购物车 从vuex中的购物车删除deleteSelectFood中的内容
Object.keys(this.deleteSelectFood).forEach((restaurant_id) => {
let restaurant = this.deleteSelectFood[restaurant_id]; //商店
Object.keys(restaurant).forEach(food_id => { //要删除的商品
if (Number(food_id) && restaurant[food_id]) {
this.$store.dispatch('deleteFood', {restaurant_id, food_id})//删除购物车数据
delete this.selectFood[restaurant_id][food_id];// 删除selectFood中该餐馆的指定食品
}
this.allSelect(restaurant_id, false);//重置选中列表为false 因为删除商品后 页面所有商品全部不选中
delete restaurant[food_id];// 删除deleteSelectFood中该餐馆中指定食品
})
})
this.editStatus = false;// 从编辑状态变为正常状态
this.emptyCart = !Object.keys(this.cartList).length;// 删除完商品后判断一下购物车是否为空
}
//删除食物
[types.DELETE_FOOD](state, {restaurant_id, food_id}) {
let cart = state.cartList;// 购物车
let restaurant = cart[restaurant_id];// 餐馆
let num = restaurant[food_id].num;// 餐馆中的该食品总数
let price = restaurant[food_id].price;// 餐馆中该食品的价格
restaurant.totalNum -= num;// 餐馆总食品数量 - 餐馆中该食品的总数
delete(restaurant[food_id]);// 删除参观中该食品
if (restaurant.totalNum === 0) {// 如果餐馆中食品数量为0 从购物车中删除该餐馆
delete(cart[restaurant_id]);
} else {//否则修改餐馆的总价格 = 餐馆的总价格 - 食品数量 * 食品总数
restaurant.totalPrice = Number((restaurant.totalPrice - price * num).toFixed(2));
}
state.cartList = {...cart};// 更改vuex中的购物车内容
localStorage.setItem('cartList', JSON.stringify(state.cartList));// 将购物车中的内容保存在localStorage中
}
allSelect(restaurant_id, boolean) {//设置某个餐馆的食品是全选还是不全选
this.selectFood[restaurant_id]['allSelect'] = boolean;//先设置该餐馆的全选标志
Object.keys(this.selectFood[restaurant_id]).forEach(el => {
//遍历该餐馆下的所有食品 为每个食品设置全选/全不选
if (Number(el)) this.selectFood[restaurant_id][el] = boolean;
})
if (boolean) {//如果是选中 计算价格 遍历餐馆中的所有食物 计算总价 = 商品数量 * 价格
let restaurant = this.cartList[restaurant_id];
Object.keys(restaurant).forEach(el => {
if (Number(el)) {
this.selectFood[restaurant_id]['totalPrice'] += restaurant[el]['num'] * restaurant[el]['price'];
}
});
} else {//取消全选 selectFood中该餐馆的totalPrice为0
this.selectFood[restaurant_id]['totalPrice'] = 0;
}
this.selectFood = {...this.selectFood}; //拓展运算符使vue更新视图
}
商品
遍历前面遍历出来的商店信息里面的商品信息
- editStatus为true(在编辑状态下)并且如果该商品被选中 该商品前面的小圆圈展示√这个iconfont 点击这个小圆圈后 该商品取消删除 如果该商品未被选中 点击后 选中该商品
<span class="selected delete-selected"
v-if="editStatus && deleteSelectFood[restaurant_id][foodKey] === true"
@click="cancelSelectDelete(restaurant_id,foodKey)">
<i class="iconfont"></i>
</span>
<span class="select delete-select"
v-else-if="editStatus"
@click="selectDelete(restaurant_id,foodKey)">
</span>
<script>
cancelSelectDelete(restaurant_id, foodKey) {//取消删除选中
this.deleteSelectFood[restaurant_id][foodKey] = false;//该商品删除选中为false
this.deleteSelectFood[restaurant_id]['allSelect'] = false;//全选标志为false
this.deleteSelectFood = {...this.deleteSelectFood};//拓展运算符使vue更新视图
}
selectDelete(restaurant_id, foodKey) { //选中删除商品
this.deleteSelectFood[restaurant_id][foodKey] = true; //该商品选中置为true
//判读是否全选
let newObj = {...this.deleteSelectFood[restaurant_id]};
let allSelect = this.isAllSelect(newObj, restaurant_id);
this.deleteSelectFood[restaurant_id]['allSelect'] = allSelect;
this.deleteSelectFood = {...this.deleteSelectFood}; //拓展运算符使vue更新视图
}
isAllSelect(newObj) {//判断商品是否全选中了 如果全选中那么商家头像左边的按钮对应选中
delete newObj.allSelect;
let values = Object.values(newObj);
let noAllSelect = values.some((el) => {
if (el === false)
return true;
});
return !noAllSelect;
}
</script>
- editStatus为false(在非编辑状态下)并且如果该商品被选中 该商品前面的小圆圈展示√这个iconfont 点击这个小圆圈后 该商品取消删除 如果该商品未被选中 点击后 选中该商品
<span
class="selected"
v-if="!editStatus && selectFood[restaurant_id][foodKey] === true"
@click="cancelSelect(restaurant_id,foodKey)">
<i class="iconfont"></i>
</span>
<span
class="select"
v-else-if="!editStatus"
@click="select(restaurant_id,foodKey)">
</span>
<script>
cancelSelect(restaurant_id, foodKey) { //取消选中商品
this.selectFood[restaurant_id][foodKey] = false; //该商品取消选中
this.selectFood[restaurant_id]['allSelect'] = false; //全选标志为false
let cartFoodData = this.cartList[restaurant_id][foodKey]; //购物车中 该商品信息
this.selectFood[restaurant_id]['totalPrice'] -= cartFoodData['num'] * cartFoodData['price']; //修改价格
this.selectFood = {...this.selectFood}; //拓展运算符使vue更新视图
}
select(restaurant_id, foodKey) { //选中商品
this.selectFood[restaurant_id][foodKey] = true; //该商品选中置true
let cartFoodData = this.cartList[restaurant_id][foodKey]; //购物车中 该商品信息
this.selectFood[restaurant_id]['totalPrice'] += cartFoodData['num'] * cartFoodData['price']; //修改价格
//判读是否全选
let newObj = {...this.selectFood[restaurant_id]};
let allSelect = this.isAllSelect(newObj, restaurant_id);
this.selectFood[restaurant_id]['allSelect'] = allSelect;
this.selectFood = {...this.selectFood}; //拓展运算符使vue更新视图
}
</script>
展示食品图片、名称、数量、价格
<div class="picture-container">
<img :src="food.foods_pic">
</div>
<div class="info">
<span class="name">{{food.name}}</span>
<div>
<span class="num">x{{food.num}}</span>
<span class="price">¥{{food.price}}</span>
editStatus为false(在非编辑状态下)展示“去结算” 点击后执行submit方法 进行提交前的判断 有无商品呈现的“去结算”不一样 动态为其绑定样式
<div class="bottom" v-show="!editStatus">
<span class="submit"
@click="submit(restaurant_id)"
:class="{active:!selectFood[restaurant_id]['totalPrice']}">去结算
</span>
<!--取出总价展示-->
<span class="total-price">¥{{selectFood[restaurant_id]['totalPrice'].toFixed(2)}}</span>
</div>
<script>
submit(restaurant_id) { //提交订单
if (!this.selectFood[restaurant_id].totalPrice) return;//如果没有选中食物 不能提交订单
let restaurant = this.selectFood[restaurant_id];//选中食物的餐馆
let foods = {
totalPrice: 0,
totalNum: 0
};
Object.keys(restaurant).forEach(el => {//计算价格 遍历餐馆中的食物
if (Number(el) && restaurant[el]) {
let food = this.cartList[restaurant_id][el];
foods[el] = food;// 把食品保存在foods中
foods['totalPrice'] += food.num * food.price;// 计算价格
foods['totalNum'] += food.num;// 计算商品数量
}
})
let data = {
restaurant_id,
foods
};
localStorage.setItem('confirmOrderData', JSON.stringify(data));// 将商品保存在localStorage中
this.$router.push({path: '/confirm_order'});// 跳转到订单确认页面
}
</script>