在原有的页面上添加 ,底部 已加载完毕 分割线 避免被购物车挡住 原有页面如下 : <template>
<view class="shop-container">
<!-- 顶部固定区域 -->
<view class="fixed-header">
<!-- 搜索栏 -->
<view class="search-bar">
<uni-search-bar
placeholder="搜索菜品"
radius="100"
@confirm="searchDish"
@input="searchInput"
cancelButton="none"
/>
</view>
<!-- 菜品分类 -->
<scroll-view class="category-scroll" scroll-x="true">
<view
v-for="(category, index) in categories"
:key="index"
class="category-item"
:class="{ active: currentCategory === index }"
@click="changeCategory(index)"
>
{{ category.name }}
</view>
</scroll-view>
</view>
<!-- 菜品列表 -->
<scroll-view class="dish-list" scroll-y="true">
<view v-for="(dish, index) in filteredDishes" :key="dish.id" class="dish-item">
<!-- 菜品图片 -->
<image class="dish-image" :src="dish.image" mode="aspectFill" />
<!-- 菜品信息 -->
<view class="dish-info">
<text class="dish-name">{{ dish.name }}</text>
<text class="dish-price">¥{{ dish.price.toFixed(2) }}</text>
<text class="dish-stock" :class="{ 'low-stock': dish.stock < 5 }">
剩余: {{ dish.stock }}份
</text>
</view>
<!-- 数量选择器 -->
<view class="quantity-selector" v-if="cartItemQuantity(dish.id) > 0">
<button class="quantity-btn" @click="decreaseQuantity(dish)">
<uni-icons type="minus" size="16" color="#ff6b6b"></uni-icons>
</button>
<text class="quantity-text">{{ cartItemQuantity(dish.id) }}</text>
<button
class="quantity-btn"
:disabled="cartItemQuantity(dish.id) >= dish.stock"
@click="increaseQuantity(dish)"
>
<uni-icons type="plus" size="16" color="#ff6b6b"></uni-icons>
</button>
</view>
<!-- 添加按钮 -->
<view class="add-btn-container" v-else>
<button v-if="dish.stock > 0"
class="add-btn"
:disabled="dish.stock <= 0"
@click="addToCart(dish)">
<uni-icons type="plusempty" size="20" color="#fff"></uni-icons>
</button>
<text v-if="dish.stock <= 0" class="sold-out-text">已售罄</text>
</view>
</view>
</scroll-view>
<!-- 购物车底部栏 -->
<view class="cart-bar" @click="showCartDetail">
<view class="cart-icon-container">
<uni-icons type="cart-filled" size="30" color="#fff"></uni-icons>
<view v-if="cartItemCount > 0" class="cart-badge">{{ cartItemCount }}</view>
</view>
<text class="total-price">¥{{ totalPrice.toFixed(2) }}</text>
<button class="checkout-btn" :disabled="cartItemCount === 0">去结算</button>
</view>
<!-- 购物车详情弹窗 -->
<uni-popup ref="cartPopup" type="bottom" :maskClick="false">
<view class="cart-detail">
<view class="cart-header">
<text class="cart-title">已选菜品</text>
<uni-icons type="close" size="24" color="#999" @click="closeCartDetail"></uni-icons>
</view>
<scroll-view class="cart-list" scroll-y="true">
<view v-for="(item, index) in cart" :key="item.id" class="cart-item">
<image class="cart-item-image" :src="item.image" mode="aspectFill" />
<view class="cart-item-info">
<text class="cart-item-name">{{ item.name }}</text>
<text class="cart-item-price">¥{{ item.price.toFixed(2) }}</text>
</view>
<view class="cart-item-quantity">
<button class="cart-quantity-btn" @click="decreaseCartQuantity(item)">
<uni-icons type="minus" size="16" color="#ff6b6b"></uni-icons>
</button>
<text class="cart-quantity-text">{{ item.quantity }}</text>
<button
class="cart-quantity-btn"
:disabled="item.quantity >= item.stock"
@click="increaseCartQuantity(item)"
>
<uni-icons type="plus" size="16" color="#ff6b6b"></uni-icons>
</button>
</view>
</view>
</scroll-view>
<view class="cart-footer">
<text class="cart-total">总计: ¥{{ totalPrice.toFixed(2) }}</text>
<button class="cart-checkout-btn" @click="checkout">去结算</button>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
export default {
data() {
return {
currentCategory: 0, // 当前选中的分类索引
searchKeyword: '', // 搜索关键词
cart: [], // 购物车
// 菜品分类
categories: [
{ id: 0, name: '全部' },
{ id: 1, name: '热销' },
{ id: 2, name: '主食' },
{ id: 3, name: '汤类' },
{ id: 4, name: '小吃' },
{ id: 5, name: '饮品' }
],
// 菜品数据
dishes: [
{
id: 1,
name: '鱼香肉丝',
price: 38,
stock: 15,
image: '/static/images/dishes/1.jpeg',
category: 1
},
{
id: 2,
name: '宫保鸡丁',
price: 42,
stock: 8,
image: '/static/images/dishes/2.jpeg',
category: 1
},
{
id: 3,
name: '麻婆豆腐',
price: 28,
stock: 0,
image: '/static/images/dishes/3.jpg',
category: 1
},
{
id: 4,
name: '扬州炒饭',
price: 25,
stock: 12,
image: '/static/images/dishes/4.jpeg',
category: 2
},
{
id: 5,
name: '番茄鸡蛋面',
price: 22,
stock: 20,
image: '/static/images/dishes/4.jpeg',
category: 2
},
{
id: 6,
name: '酸辣汤',
price: 18,
stock: 5,
image: '/static/images/dishes/4.jpeg',
category: 3
},
{
id: 7,
name: '春卷',
price: 15,
stock: 3,
image: '/static/images/dishes/4.jpeg',
category: 4
},
{
id: 8,
name: '冰镇酸梅汤',
price: 12,
stock: 25,
image: '/static/images/dishes/dish08.jpg',
category: 5
}
]
}
},
computed: {
// 过滤后的菜品列表
filteredDishes() {
let result = [...this.dishes];
// 按分类过滤
if (this.currentCategory > 0) {
result = result.filter(dish => dish.category === this.currentCategory);
}
// 按关键词搜索
if (this.searchKeyword) {
const keyword = this.searchKeyword.toLowerCase();
result = result.filter(dish =>
dish.name.toLowerCase().includes(keyword)
);
}
return result;
},
// 购物车商品数量
cartItemCount() {
return this.cart.reduce((total, item) => total + item.quantity, 0);
},
// 总金额
totalPrice() {
return this.cart.reduce((total, item) =>
total + (item.price * item.quantity), 0);
}
},
methods: {
// 切换分类
changeCategory(index) {
this.currentCategory = index;
},
// 搜索输入
searchInput(e) {
this.searchKeyword = e.value;
},
// 搜索确认
searchDish(e) {
this.searchKeyword = e.value;
},
// 获取菜品在购物车中的数量
cartItemQuantity(dishId) {
const item = this.cart.find(item => item.id === dishId);
return item ? item.quantity : 0;
},
// 添加到购物车
addToCart(dish) {
if (dish.stock <= 0) return;
// 检查是否已在购物车
const existingItem = this.cart.find(item => item.id === dish.id);
if (existingItem) {
// 如果已在购物车,增加数量
this.increaseQuantity(dish);
} else {
// 添加到购物车
this.cart.push({
...dish,
quantity: 1
});
}
},
// 增加菜品数量
increaseQuantity(dish) {
const item = this.cart.find(item => item.id === dish.id);
if (item && item.quantity < dish.stock) {
item.quantity++;
}
},
// 减少菜品数量
decreaseQuantity(dish) {
const item = this.cart.find(item => item.id === dish.id);
if (item) {
if (item.quantity > 1) {
item.quantity--;
} else {
// 数量为1时减少则移除
this.cart = this.cart.filter(cartItem => cartItem.id !== dish.id);
}
}
},
// 增加购物车中菜品数量
increaseCartQuantity(item) {
const dish = this.dishes.find(d => d.id === item.id);
if (dish && item.quantity < dish.stock) {
item.quantity++;
}
},
// 减少购物车中菜品数量
decreaseCartQuantity(item) {
if (item.quantity > 1) {
item.quantity--;
} else {
// 数量为1时减少则移除
this.cart = this.cart.filter(cartItem => cartItem.id !== item.id);
}
},
// 显示购物车详情
showCartDetail() {
if (this.cartItemCount > 0) {
this.$refs.cartPopup.open();
}
},
// 关闭购物车详情
closeCartDetail() {
this.$refs.cartPopup.close();
},
// 结算
checkout() {
uni.showToast({
title: '结算成功',
icon: 'success'
});
// 实际开发中这里会有支付流程
this.closeCartDetail();
}
}
}
</script>
<style lang="scss" scoped>
.shop-container {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #f5f5f5;
padding-bottom: 100rpx;
}
/* 新增顶部固定容器 */
.fixed-header {
position: sticky;
top: 0;
z-index: 1000; /* 确保在顶部 */
background: white; /* 背景色,避免滚动时内容透出 */
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1); /* 添加阴影增强层次感 */
}
.search-bar {
padding: 20rpx;
background-color: #fff;
}
.category-scroll {
white-space: nowrap;
background-color: #fff;
padding: 20rpx 0;
border-bottom: 1rpx solid #eee;
}
.category-item {
display: inline-block;
padding: 10rpx 30rpx;
margin: 0 10rpx;
border-radius: 30rpx;
background-color: #f5f5f5;
font-size: 28rpx;
&.active {
background-color: #ff6b6b;
color: #fff;
}
}
.dish-list {
flex: 1;
padding: 20rpx;
/* 添加顶部内边距,避免内容被固定栏遮挡 */
// padding-top: 0;
}
.dish-item {
display: flex;
align-items: center;
background-color: #fff;
border-radius: 16rpx;
margin-bottom: 15rpx;
padding: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
}
.dish-image {
width: 180rpx;
height: 180rpx;
border-radius: 8rpx;
margin-right: 20rpx;
}
.dish-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.dish-name {
font-size: 28rpx;
font-weight: bold;
color: #333;
}
.dish-price {
font-size: 30rpx;
color: #ff6b6b;
margin-top: 10rpx;
}
.dish-stock {
font-size: 24rpx;
color: #999;
margin-top: 10rpx;
&.low-stock {
color: #ff6b6b;
}
}
.add-btn-container {
display: flex;
align-items: center;
}
.add-btn {
width: 70rpx;
height: 70rpx;
border-radius: 50%;
background-color: #ff6b6b;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
font-size: 24rpx;
padding: 0;
margin: 0;
&.disabled {
background-color: #ccc;
}
}
.sold-out-text {
font-size: 28rpx;
color: #999;
padding: 10rpx 20rpx;
background-color: #f5f5f5;
border-radius: 8rpx;
}
.quantity-selector {
display: flex;
align-items: center;
background-color: #fff;
border-radius: 40rpx;
padding: 6rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.quantity-btn {
width: 50rpx;
height: 50rpx;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
padding: 0;
margin: 0;
background-color: #fff;
border: 1rpx solid #eee;
}
.quantity-text {
font-size: 28rpx;
min-width: 60rpx;
text-align: center;
font-weight: bold;
}
.cart-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 100rpx;
background-color: #333;
display: flex;
align-items: center;
padding: 0 30rpx;
color: #fff;
z-index: 999;
}
.cart-icon-container {
position: relative;
margin-right: 20rpx;
}
.cart-badge {
position: absolute;
top: -10rpx;
right: -10rpx;
background-color: #ff6b6b;
color: #fff;
border-radius: 50%;
width: 40rpx;
height: 40rpx;
display: flex;
justify-content: center;
align-items: center;
font-size: 24rpx;
}
.total-price {
flex: 1;
font-size: 36rpx;
font-weight: bold;
}
.checkout-btn {
background-color: #ff6b6b;
color: #fff;
border-radius: 50rpx;
padding: 0 40rpx;
height: 70rpx;
line-height: 70rpx;
font-size: 30rpx;
&[disabled] {
background-color: #999;
opacity: 0.6;
}
}
/* 购物车详情弹窗样式 */
.cart-detail {
background-color: #fff;
border-top-left-radius: 20rpx;
border-top-right-radius: 20rpx;
padding: 30rpx;
max-height: 80vh;
display: flex;
flex-direction: column;
}
.cart-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #eee;
margin-bottom: 20rpx;
}
.cart-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
}
.cart-list {
flex: 1;
max-height: 60vh;
}
.cart-item {
display: flex;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f5f5f5;
}
.cart-item-image {
width: 120rpx;
height: 120rpx;
border-radius: 8rpx;
margin-right: 20rpx;
}
.cart-item-info {
flex: 1;
}
.cart-item-name {
font-size: 30rpx;
color: #333;
margin-bottom: 10rpx;
}
.cart-item-price {
font-size: 28rpx;
color: #ff6b6b;
}
.cart-item-quantity {
display: flex;
align-items: center;
}
.cart-quantity-btn {
width: 50rpx;
height: 50rpx;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
padding: 0;
margin: 0 10rpx;
background-color: #fff;
border: 1rpx solid #eee;
}
.cart-quantity-text {
font-size: 28rpx;
min-width: 60rpx;
text-align: center;
font-weight: bold;
}
.cart-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 20rpx;
padding-top: 20rpx;
border-top: 1rpx solid #eee;
}
.cart-total {
font-size: 36rpx;
font-weight: bold;
color: #ff6b6b;
}
.cart-checkout-btn {
background-color: #ff6b6b;
color: #fff;
border-radius: 50rpx;
padding: 0 40rpx;
height: 80rpx;
line-height: 80rpx;
font-size: 32rpx;
}
</style>