|
@@ -98,7 +98,7 @@
|
|
|
<span class="fs-24 fw-400 fc-3">¥</span>
|
|
<span class="fs-24 fw-400 fc-3">¥</span>
|
|
|
<span
|
|
<span
|
|
|
class="fs-40 fw-b fc-3">{{info.seckill_money>0?info.seckill_money:info.price}}</span>
|
|
class="fs-40 fw-b fc-3">{{info.seckill_money>0?info.seckill_money:info.price}}</span>
|
|
|
- <span class="fs-24 fc-9">/份起</span>
|
|
|
|
|
|
|
+ <span class="fs-24 fc-9">/份起</span>
|
|
|
</view>
|
|
</view>
|
|
|
<view class="display-flex align-items-center" v-if="info.spec_type == 1">
|
|
<view class="display-flex align-items-center" v-if="info.spec_type == 1">
|
|
|
<image v-show="info.num > 0" class="wh-44" @click="addred(1,info)"
|
|
<image v-show="info.num > 0" class="wh-44" @click="addred(1,info)"
|
|
@@ -197,7 +197,8 @@
|
|
|
message="快去选购商品吧!~"></en-blank>
|
|
message="快去选购商品吧!~"></en-blank>
|
|
|
</view>
|
|
</view>
|
|
|
<view class="pop-shop-buttom-money box-border-box" @click="openBuyCrad()">
|
|
<view class="pop-shop-buttom-money box-border-box" @click="openBuyCrad()">
|
|
|
- <view class="shop-buttom-money-1 bgc-f flex-justify-space align-items-center pl-24 box-border-box pr-8 b-rad-200">
|
|
|
|
|
|
|
+ <view
|
|
|
|
|
+ class="shop-buttom-money-1 bgc-f flex-justify-space align-items-center pl-24 box-border-box pr-8 b-rad-200">
|
|
|
<view class="align-items-center">
|
|
<view class="align-items-center">
|
|
|
<image class="gwc-img mr-36" src="@/static/img/order-food/gwc-img.png" mode="scaleToFill">
|
|
<image class="gwc-img mr-36" src="@/static/img/order-food/gwc-img.png" mode="scaleToFill">
|
|
|
</image>
|
|
</image>
|
|
@@ -275,7 +276,6 @@
|
|
|
heightTwo: '',
|
|
heightTwo: '',
|
|
|
topHeight: '',
|
|
topHeight: '',
|
|
|
idMark: '', //滚动自适应参数
|
|
idMark: '', //滚动自适应参数
|
|
|
- idMarkTwo: '', //滚动自适应参数
|
|
|
|
|
type: '', //默认分类标识
|
|
type: '', //默认分类标识
|
|
|
categoryList: [],
|
|
categoryList: [],
|
|
|
goodsList: [],
|
|
goodsList: [],
|
|
@@ -285,23 +285,52 @@
|
|
|
pack_price: 0,
|
|
pack_price: 0,
|
|
|
total_goods_money: 0,
|
|
total_goods_money: 0,
|
|
|
goods_list: [],
|
|
goods_list: [],
|
|
|
- }
|
|
|
|
|
|
|
+ },
|
|
|
|
|
+ categoryTops: [], // 存储每个分类的top位置
|
|
|
|
|
+ isScrolling: false, // 防止滚动事件冲突
|
|
|
|
|
+ activeScroll: false, // 是否正在滚动
|
|
|
|
|
+ scrollTimer: null, // 滚动计时器
|
|
|
|
|
+ observer: null, // IntersectionObserver实例
|
|
|
|
|
+ categoryDomInfos: [], // 存储分类DOM信息
|
|
|
|
|
+ isManualScroll: false, // 是否是手动触发滚动
|
|
|
|
|
+ lastActiveCategory: '', // 记录上一次激活的分类,避免重复更新
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ // 在onUnload中销毁监听
|
|
|
|
|
+ onUnload() {
|
|
|
|
|
+ if (this.observer) {
|
|
|
|
|
+ this.observer.disconnect();
|
|
|
|
|
+ this.observer = null;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (this.scrollTimer) {
|
|
|
|
|
+ clearTimeout(this.scrollTimer);
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
onShow() {
|
|
onShow() {
|
|
|
this.getShopIngList();
|
|
this.getShopIngList();
|
|
|
|
|
+ // 重新计算分类位置
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ this.initCategoryPositions();
|
|
|
|
|
+ }, 300);
|
|
|
},
|
|
},
|
|
|
onLoad(e) {
|
|
onLoad(e) {
|
|
|
cartStore.setShopId();
|
|
cartStore.setShopId();
|
|
|
this.getshopInfo();
|
|
this.getshopInfo();
|
|
|
},
|
|
},
|
|
|
|
|
+ onReady() {
|
|
|
|
|
+ // 确保DOM完全渲染后初始化位置
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ this.initCategoryPositions();
|
|
|
|
|
+ }, 800);
|
|
|
|
|
+ },
|
|
|
mounted() {},
|
|
mounted() {},
|
|
|
onReachBottom(e) {},
|
|
onReachBottom(e) {},
|
|
|
// 监听页面滚动
|
|
// 监听页面滚动
|
|
|
onPageScroll(e) {
|
|
onPageScroll(e) {
|
|
|
// e.scrollTop 获取滚动条距离页面顶部的距离
|
|
// e.scrollTop 获取滚动条距离页面顶部的距离
|
|
|
this.scrollTop = e.scrollTop
|
|
this.scrollTop = e.scrollTop
|
|
|
- this.opacity = (Number(this.scrollTop) - 30)
|
|
|
|
|
|
|
+ // this.opacity = (Number(this.scrollTop) - 30)
|
|
|
|
|
+ this.opacity = Math.min((this.scrollTop - 30) / 100, 1);
|
|
|
// 可以根据滚动位置执行相应逻辑
|
|
// 可以根据滚动位置执行相应逻辑
|
|
|
if (e.scrollTop > 25) {
|
|
if (e.scrollTop > 25) {
|
|
|
this.navBgType = true
|
|
this.navBgType = true
|
|
@@ -313,8 +342,202 @@
|
|
|
} else {
|
|
} else {
|
|
|
this.menuLeftType = false
|
|
this.menuLeftType = false
|
|
|
}
|
|
}
|
|
|
|
|
+ // 优化:只在非手动滚动且菜单固定时更新激活分类
|
|
|
|
|
+ if (!this.isManualScroll && this.menuLeftType) {
|
|
|
|
|
+ this.updateActiveCategoryOnScroll();
|
|
|
|
|
+ }
|
|
|
},
|
|
},
|
|
|
methods: {
|
|
methods: {
|
|
|
|
|
+ // 初始化分类位置信息
|
|
|
|
|
+ initCategoryPositions() {
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
|
+ const query = uni.createSelectorQuery().in(this);
|
|
|
|
|
+
|
|
|
|
|
+ // 清空之前的 DOM 信息
|
|
|
|
|
+ this.categoryDomInfos = [];
|
|
|
|
|
+ this.categoryTops = [];
|
|
|
|
|
+
|
|
|
|
|
+ // 收集所有分类的位置信息
|
|
|
|
|
+ this.goodsList.forEach((category, index) => {
|
|
|
|
|
+ if (category.type) {
|
|
|
|
|
+ query.select(`#scroll${category.type}`).boundingClientRect();
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ query.exec((res) => {
|
|
|
|
|
+ if (!res || res.length === 0) return;
|
|
|
|
|
+
|
|
|
|
|
+ this.categoryDomInfos = res.map((rect, index) => {
|
|
|
|
|
+ if (rect && this.goodsList[index]) {
|
|
|
|
|
+ const categoryInfo = {
|
|
|
|
|
+ id: this.goodsList[index].type,
|
|
|
|
|
+ top: rect.top,
|
|
|
|
|
+ height: rect.height,
|
|
|
|
|
+ index: index
|
|
|
|
|
+ };
|
|
|
|
|
+ this.categoryTops.push(categoryInfo);
|
|
|
|
|
+ return categoryInfo;
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }).filter(item => item !== null);
|
|
|
|
|
+
|
|
|
|
|
+ console.log('分类位置信息:', this.categoryDomInfos);
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ // 更新激活的分类
|
|
|
|
|
+ updateActiveCategoryOnScroll() {
|
|
|
|
|
+ if (this.scrollTimer) {
|
|
|
|
|
+ clearTimeout(this.scrollTimer);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.scrollTimer = setTimeout(() => {
|
|
|
|
|
+ this.findCurrentCategory();
|
|
|
|
|
+ }, 150); // 增加防抖时间
|
|
|
|
|
+ },
|
|
|
|
|
+ // 查找当前应该激活的分类
|
|
|
|
|
+ findCurrentCategory() {
|
|
|
|
|
+ if (this.categoryDomInfos.length === 0 || !this.goodsList) return;
|
|
|
|
|
+
|
|
|
|
|
+ const query = uni.createSelectorQuery().in(this);
|
|
|
|
|
+ query.selectViewport().scrollOffset();
|
|
|
|
|
+
|
|
|
|
|
+ query.exec((res) => {
|
|
|
|
|
+ if (!res || !res[0]) return;
|
|
|
|
|
+
|
|
|
|
|
+ const scrollTop = res[0].scrollTop;
|
|
|
|
|
+
|
|
|
|
|
+ // 获取吸顶区域总高度
|
|
|
|
|
+ const stickyHeight = this.getStickyHeight();
|
|
|
|
|
+
|
|
|
|
|
+ // 阈值位置:视口顶部 + 吸顶高度 + 缓冲区域(分类标题高度的 1/3)
|
|
|
|
|
+ const threshold = scrollTop + stickyHeight + 10;
|
|
|
|
|
+
|
|
|
|
|
+ // 找当前应该激活的分类
|
|
|
|
|
+ let currentCategoryId = this.categoryList[0]?.category_id;
|
|
|
|
|
+ let found = false;
|
|
|
|
|
+
|
|
|
|
|
+ // 从后往前遍历,找到最后一个在阈值上方的分类
|
|
|
|
|
+ for (let i = this.categoryDomInfos.length - 1; i >= 0; i--) {
|
|
|
|
|
+ const category = this.categoryDomInfos[i];
|
|
|
|
|
+ if (category) {
|
|
|
|
|
+ // 元素顶部位置(相对于视口)+ 滚动距离 = 相对于页面顶部的位置
|
|
|
|
|
+ const elementTop = category.top + scrollTop;
|
|
|
|
|
+
|
|
|
|
|
+ // 如果元素顶部在阈值上方或刚好对齐
|
|
|
|
|
+ if (elementTop <= threshold) {
|
|
|
|
|
+ currentCategoryId = category.id;
|
|
|
|
|
+ found = true;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果都没找到,说明第一个分类已经滚动过去了,使用第一个分类
|
|
|
|
|
+ if (!found && this.categoryDomInfos.length > 0) {
|
|
|
|
|
+ currentCategoryId = this.categoryDomInfos[0].id;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 只有当分类真正改变时才更新,避免频繁触发
|
|
|
|
|
+ if (currentCategoryId && this.type !== currentCategoryId) {
|
|
|
|
|
+ console.log('滚动激活分类:', currentCategoryId);
|
|
|
|
|
+ this.type = currentCategoryId;
|
|
|
|
|
+ this.lastActiveCategory = currentCategoryId;
|
|
|
|
|
+ this.$forceUpdate();
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ // 优化滚动到分类的方法
|
|
|
|
|
+ scrollToCategory(categoryId) {
|
|
|
|
|
+ this.isManualScroll = true;
|
|
|
|
|
+
|
|
|
|
|
+ const query = uni.createSelectorQuery().in(this);
|
|
|
|
|
+ const selector = `#scroll${categoryId}`;
|
|
|
|
|
+
|
|
|
|
|
+ query.select(selector).boundingClientRect();
|
|
|
|
|
+ query.selectViewport().scrollOffset();
|
|
|
|
|
+
|
|
|
|
|
+ query.exec((res) => {
|
|
|
|
|
+ if (res[0] && res[1]) {
|
|
|
|
|
+ const categoryRect = res[0];
|
|
|
|
|
+ const scrollTop = res[1].scrollTop;
|
|
|
|
|
+
|
|
|
|
|
+ // 获取吸顶区域总高度
|
|
|
|
|
+ const stickyHeight = this.getStickyHeight();
|
|
|
|
|
+
|
|
|
|
|
+ // 计算目标位置(考虑吸顶高度和缓冲)
|
|
|
|
|
+ const targetScrollTop = scrollTop + categoryRect.top - stickyHeight + 2;
|
|
|
|
|
+
|
|
|
|
|
+ // 执行滚动
|
|
|
|
|
+ uni.pageScrollTo({
|
|
|
|
|
+ scrollTop: targetScrollTop,
|
|
|
|
|
+ duration: 300,
|
|
|
|
|
+ success: () => {
|
|
|
|
|
+ // 滚动完成后,更新左侧激活状态
|
|
|
|
|
+ this.type = categoryId;
|
|
|
|
|
+ this.lastActiveCategory = categoryId;
|
|
|
|
|
+
|
|
|
|
|
+ // 延迟恢复手动滚动标记
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ this.isManualScroll = false;
|
|
|
|
|
+ }, 400);
|
|
|
|
|
+ },
|
|
|
|
|
+ fail: () => {
|
|
|
|
|
+ this.isManualScroll = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.isManualScroll = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ // 获取吸顶区域总高度(精确计算版)
|
|
|
|
|
+ getStickyHeight() {
|
|
|
|
|
+ // 导航栏高度(rpx 转 px)
|
|
|
|
|
+ const systemInfo = uni.getSystemInfoSync();
|
|
|
|
|
+ const pixelRatio = systemInfo.pixelRatio || 2;
|
|
|
|
|
+ const screenWidth = systemInfo.windowWidth || 375;
|
|
|
|
|
+ const rpxToPx = screenWidth / 750;
|
|
|
|
|
+
|
|
|
|
|
+ // 导航栏高度(从组件获取,单位 rpx)
|
|
|
|
|
+ const navHeightRpx = this.newNavHeight || 88;
|
|
|
|
|
+
|
|
|
|
|
+ // 商家信息区域高度(动态获取或估算)
|
|
|
|
|
+ let shopInfoHeightRpx = 0;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const query = uni.createSelectorQuery().in(this);
|
|
|
|
|
+ query.select('.shop-info').boundingClientRect();
|
|
|
|
|
+ // 同步获取可能失败,使用估算值
|
|
|
|
|
+ shopInfoHeightRpx = 140; // 默认估算值
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ shopInfoHeightRpx = 140;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 分类 tab 高度
|
|
|
|
|
+ const tabHeightRpx = 48;
|
|
|
|
|
+
|
|
|
|
|
+ // 额外间距
|
|
|
|
|
+ const extraPaddingRpx = 8;
|
|
|
|
|
+
|
|
|
|
|
+ // 总高度(rpx)
|
|
|
|
|
+ const totalHeightRpx = navHeightRpx;
|
|
|
|
|
+
|
|
|
|
|
+ // 转换为 px(与 pageScrollTo 保持一致)
|
|
|
|
|
+ return totalHeightRpx * rpxToPx;
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 优化选择分类的方法
|
|
|
|
|
+ selectType(item) {
|
|
|
|
|
+ if (this.type !== item.category_id) {
|
|
|
|
|
+ this.type = item.category_id;
|
|
|
|
|
+ this.$forceUpdate();
|
|
|
|
|
+
|
|
|
|
|
+ // 延迟执行滚动,确保DOM已更新
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ this.scrollToCategory(item.category_id);
|
|
|
|
|
+ }, 100);
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
shopInfo() {
|
|
shopInfo() {
|
|
|
// 获取商家详情
|
|
// 获取商家详情
|
|
|
shopInfo().then((res) => {
|
|
shopInfo().then((res) => {
|
|
@@ -342,6 +565,10 @@
|
|
|
this.goodsList = res.data
|
|
this.goodsList = res.data
|
|
|
// 从购物车数据中回显每个商品的数量
|
|
// 从购物车数据中回显每个商品的数量
|
|
|
this.updateGoodsNumFromCart()
|
|
this.updateGoodsNumFromCart()
|
|
|
|
|
+
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ this.initCategoryPositions();
|
|
|
|
|
+ }, 300);
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
},
|
|
},
|
|
@@ -435,18 +662,18 @@
|
|
|
url: 'pages/index/search-record'
|
|
url: 'pages/index/search-record'
|
|
|
})
|
|
})
|
|
|
},
|
|
},
|
|
|
- selectType(item, itemTwo) {
|
|
|
|
|
- if (this.type != item.category_id) {
|
|
|
|
|
- this.type = item.category_id;
|
|
|
|
|
- this.idMark = 'scroll' + item.category_id
|
|
|
|
|
- // 立即更新
|
|
|
|
|
- this.$forceUpdate();
|
|
|
|
|
- // 延迟执行滚动
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- this.scrollToCategorySimple(item.category_id);
|
|
|
|
|
- }, 100);
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ // selectType(item, itemTwo) {
|
|
|
|
|
+ // if (this.type != item.category_id) {
|
|
|
|
|
+ // this.type = item.category_id;
|
|
|
|
|
+ // this.idMark = 'scroll' + item.category_id
|
|
|
|
|
+ // // 立即更新
|
|
|
|
|
+ // this.$forceUpdate();
|
|
|
|
|
+ // // 延迟执行滚动
|
|
|
|
|
+ // setTimeout(() => {
|
|
|
|
|
+ // this.scrollToCategorySimple(item.category_id);
|
|
|
|
|
+ // }, 100);
|
|
|
|
|
+ // }
|
|
|
|
|
+ // },
|
|
|
// 滚动方法
|
|
// 滚动方法
|
|
|
scrollToCategorySimple(type) {
|
|
scrollToCategorySimple(type) {
|
|
|
const query = uni.createSelectorQuery();
|
|
const query = uni.createSelectorQuery();
|
|
@@ -625,9 +852,10 @@
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
<style scoped lang="scss">
|
|
|
- .min-h{
|
|
|
|
|
|
|
+ .min-h {
|
|
|
min-height: 152rpx;
|
|
min-height: 152rpx;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
.car-scroll-box {
|
|
.car-scroll-box {
|
|
|
padding: 12rpx 24rpx calc(env(safe-area-inset-bottom) + 48rpx);
|
|
padding: 12rpx 24rpx calc(env(safe-area-inset-bottom) + 48rpx);
|
|
|
}
|
|
}
|