|
|
@ -1,6 +1,6 @@ |
|
|
<template> |
|
|
<template> |
|
|
<!-- 拼团单一商家 --> |
|
|
<!-- 拼团单一商家 --> |
|
|
<view class="page1"> |
|
|
<view class="page1" @touchmove="onPageTouchMove"> |
|
|
<!-- 固定顶部导航栏(悬浮在背景图之上) --> |
|
|
<!-- 固定顶部导航栏(悬浮在背景图之上) --> |
|
|
<view class="nav-bar" |
|
|
<view class="nav-bar" |
|
|
:style="{'padding-top': menuButtonInfo.top +'px','background':lastScrollTop>200?'#fff':''}"> |
|
|
:style="{'padding-top': menuButtonInfo.top +'px','background':lastScrollTop>200?'#fff':''}"> |
|
|
@ -90,15 +90,15 @@ |
|
|
</swiper> |
|
|
</swiper> |
|
|
</view> |
|
|
</view> |
|
|
<!-- 分类栏:移到goods-list外层,position:sticky才能生效 --> |
|
|
<!-- 分类栏:移到goods-list外层,position:sticky才能生效 --> |
|
|
<view style="display: flex;height: 72%;margin-top: 10px;"> |
|
|
<view class="container" :class="{'container-sticky': isContainerSticky}" :style="{'margin-top': isContainerSticky ? '0' : '10px', 'top': isContainerSticky ? navBarHeight + 'px' : 'auto'}" style="display: flex;height: 72%;"> |
|
|
<view id="menuList" style="border-right: 1px solid #eee;font-weight: 700;font-size: 14px;"> |
|
|
<scroll-view scroll-y id="menuList" style="border-right: 1px solid #eee;font-weight: 700;font-size: 14px;height: 100%;width: 160rpx;"> |
|
|
<view class="menu1" @tap="checkTab(index)" v-for="(item,index) in menuList" :key="index" |
|
|
<view class="menu1" @tap="checkTab(index)" v-for="(item,index) in menuList" :key="index" |
|
|
:style="{'border-radius':item.checked?'10px':'','color':item.checked?'rgba(0, 35, 28, 1)':'#777','background':item.checked?'#fff':'','border-right':item.checked?'5px solid #48D1CC;':''}"> |
|
|
:style="{'border-radius':item.checked?'10px':'','color':item.checked?'rgba(0, 35, 28, 1)':'#777','background':item.checked?'#fff':'','border-right':item.checked?'5px solid #48D1CC;':''}"> |
|
|
<view style="width: 160rpx;">{{item.categoryName}}</view> |
|
|
<view style="width: 160rpx;">{{item.categoryName}}</view> |
|
|
</view> |
|
|
</view> |
|
|
</view> |
|
|
</scroll-view> |
|
|
<view class="goods-list"> |
|
|
<scroll-view class="goods-list" scroll-y :scroll-into-view="scrollIntoViewId" :scroll-top="goodsListScrollTop" @scroll="onGoodsListScroll" @scrolltoupper="onGoodsListScrollToTop" :scroll-with-animation="true"> |
|
|
<view class="goods-member" v-for="(item,index) in productItem" :key="index" |
|
|
<view class="goods-member" :id="'category-' + item.categoryId" v-for="(item,index) in productItem" :key="index" |
|
|
@tap="goDetail('product',item)"> |
|
|
@tap="goDetail('product',item)"> |
|
|
<view class="goods-top"> |
|
|
<view class="goods-top"> |
|
|
<view class="goods-img"> |
|
|
<view class="goods-img"> |
|
|
@ -143,7 +143,7 @@ |
|
|
</view> |
|
|
</view> |
|
|
<uni-load-more :status="loadStatus" @change="onChange" /> |
|
|
<uni-load-more :status="loadStatus" @change="onChange" /> |
|
|
<view style="height: 80px;width: 100%;"></view> |
|
|
<view style="height: 80px;width: 100%;"></view> |
|
|
</view> |
|
|
</scroll-view> |
|
|
|
|
|
|
|
|
</view> |
|
|
</view> |
|
|
</view> |
|
|
</view> |
|
|
@ -500,6 +500,13 @@ |
|
|
lastScrollTop: 0, |
|
|
lastScrollTop: 0, |
|
|
// 防止切换分类之后onPageScroll闪回的标志 |
|
|
// 防止切换分类之后onPageScroll闪回的标志 |
|
|
isSwitching: false, |
|
|
isSwitching: false, |
|
|
|
|
|
// 吸顶与滚动控制 |
|
|
|
|
|
isContainerSticky: false, |
|
|
|
|
|
containerOriginalTop: 0, |
|
|
|
|
|
scrollIntoViewId: '', |
|
|
|
|
|
goodsListScrollTop: 0, |
|
|
|
|
|
isAutoScrolling: false, |
|
|
|
|
|
pageScrollTop: 0, |
|
|
searchForm: { |
|
|
searchForm: { |
|
|
shopId: '', |
|
|
shopId: '', |
|
|
delFlag: 1, |
|
|
delFlag: 1, |
|
|
@ -606,15 +613,95 @@ |
|
|
this.navBarHeight = info.statusBarHeight + 40; |
|
|
this.navBarHeight = info.statusBarHeight + 40; |
|
|
}, |
|
|
}, |
|
|
onReady() { |
|
|
onReady() { |
|
|
// 记录分类栏相对页面的偏移量,用于上滑检测 |
|
|
// 记录container相对页面的初始偏移量 |
|
|
setTimeout(() => { |
|
|
setTimeout(() => { |
|
|
const query = uni.createSelectorQuery().in(this); |
|
|
const query = uni.createSelectorQuery().in(this); |
|
|
query.select('#menuList').boundingClientRect(rect => { |
|
|
query.select('.container').boundingClientRect(rect => { |
|
|
if (rect) this.menuListOffsetTop = rect.top + this.lastScrollTop; |
|
|
if (rect) { |
|
|
|
|
|
this.containerOriginalTop = rect.top; |
|
|
|
|
|
this.menuListOffsetTop = rect.top; |
|
|
|
|
|
} |
|
|
}).exec(); |
|
|
}).exec(); |
|
|
}, 500); |
|
|
}, 500); |
|
|
}, |
|
|
}, |
|
|
|
|
|
onPageScroll(e) { |
|
|
|
|
|
this.lastScrollTop = e.scrollTop; |
|
|
|
|
|
// 当页面滚动到container应该触顶的位置时,启用吸顶 |
|
|
|
|
|
const stickyThreshold = this.containerOriginalTop - this.navBarHeight; |
|
|
|
|
|
if (e.scrollTop >= stickyThreshold && !this.isContainerSticky) { |
|
|
|
|
|
this.isContainerSticky = true; |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
methods: { |
|
|
methods: { |
|
|
|
|
|
// 页面touchmove事件:吸顶后阻止页面整体滑动(让goods-list接管滚动) |
|
|
|
|
|
onPageTouchMove(e) { |
|
|
|
|
|
// 吸顶状态下不需要额外处理,scroll-view会自己处理 |
|
|
|
|
|
}, |
|
|
|
|
|
// goods-list滚动事件:检测分类切换 + 滚回顶部取消吸顶 |
|
|
|
|
|
onGoodsListScroll(e) { |
|
|
|
|
|
if (this.isAutoScrolling) return; |
|
|
|
|
|
const scrollTop = e.detail.scrollTop; |
|
|
|
|
|
// 向下滑动到顶部时,取消吸顶 |
|
|
|
|
|
if (scrollTop <= 0 && this.isContainerSticky) { |
|
|
|
|
|
this.isContainerSticky = false; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
// 根据滚动位置自动选中对应分类 |
|
|
|
|
|
this.detectCurrentCategory(); |
|
|
|
|
|
}, |
|
|
|
|
|
onGoodsListScrollToTop() { |
|
|
|
|
|
if (this.isAutoScrolling) return; |
|
|
|
|
|
// 滚到顶部了,取消吸顶 |
|
|
|
|
|
this.isContainerSticky = false; |
|
|
|
|
|
}, |
|
|
|
|
|
// 检测当前可见的分类 |
|
|
|
|
|
detectCurrentCategory() { |
|
|
|
|
|
if (this.isSwitching) return; |
|
|
|
|
|
const query = uni.createSelectorQuery().in(this); |
|
|
|
|
|
// 获取goods-list中所有goods-member的位置 |
|
|
|
|
|
query.selectAll('.goods-member').boundingClientRect(); |
|
|
|
|
|
query.select('.goods-list').boundingClientRect(); |
|
|
|
|
|
query.exec((res) => { |
|
|
|
|
|
if (!res || !res[0] || !res[1]) return; |
|
|
|
|
|
const items = res[0]; |
|
|
|
|
|
const listRect = res[1]; |
|
|
|
|
|
const listTop = listRect.top; |
|
|
|
|
|
let currentCategoryId = ''; |
|
|
|
|
|
// 找到第一个顶部在goods-list可视区域内或刚过顶部的item |
|
|
|
|
|
for (let i = items.length - 1; i >= 0; i--) { |
|
|
|
|
|
if (items[i].top <= listTop + 10) { |
|
|
|
|
|
// 从productItem中获取categoryId |
|
|
|
|
|
if (this.productItem[i]) { |
|
|
|
|
|
currentCategoryId = this.productItem[i].categoryId; |
|
|
|
|
|
} |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (currentCategoryId !== '' || currentCategoryId === '') { |
|
|
|
|
|
// 在menuList中找到匹配的菜单并选中 |
|
|
|
|
|
let found = false; |
|
|
|
|
|
for (let i = 0; i < this.menuList.length; i++) { |
|
|
|
|
|
if (String(this.menuList[i].id) === String(currentCategoryId)) { |
|
|
|
|
|
if (!this.menuList[i].checked) { |
|
|
|
|
|
for (let j = 0; j < this.menuList.length; j++) { |
|
|
|
|
|
this.menuList[j].checked = (j === i); |
|
|
|
|
|
} |
|
|
|
|
|
this.$forceUpdate(); |
|
|
|
|
|
} |
|
|
|
|
|
found = true; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
// 如果没找到匹配的分类(如categoryId为空),选中"猜你喜欢" |
|
|
|
|
|
if (!found && currentCategoryId === '') { |
|
|
|
|
|
for (let j = 0; j < this.menuList.length; j++) { |
|
|
|
|
|
this.menuList[j].checked = (j === 0); |
|
|
|
|
|
} |
|
|
|
|
|
this.$forceUpdate(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
}, |
|
|
getProduct(categoryId) { |
|
|
getProduct(categoryId) { |
|
|
let that = this; |
|
|
let that = this; |
|
|
this.loadStatus = 'loading'; |
|
|
this.loadStatus = 'loading'; |
|
|
@ -666,15 +753,41 @@ |
|
|
}).catch((res) => {}) |
|
|
}).catch((res) => {}) |
|
|
}, |
|
|
}, |
|
|
checkTab(index) { |
|
|
checkTab(index) { |
|
|
|
|
|
this.isSwitching = true; |
|
|
for (let i = 0; i < this.menuList.length; i++) { |
|
|
for (let i = 0; i < this.menuList.length; i++) { |
|
|
this.menuList[i].checked = (i === index); |
|
|
this.menuList[i].checked = (i === index); |
|
|
} |
|
|
} |
|
|
// 重置分页 |
|
|
const selectedCategory = this.menuList[index]; |
|
|
this.searchForm.pageNum = 1; |
|
|
// 如果是"猜你喜欢"(id为空),滚动到顶部 |
|
|
this.pageNum = 1; |
|
|
if (!selectedCategory.id && selectedCategory.id !== 0) { |
|
|
this.total = 1; |
|
|
this.goodsListScrollTop = 0; |
|
|
this.productItem = []; |
|
|
this.$nextTick(() => { |
|
|
this.getProduct(this.menuList[index].id); |
|
|
this.goodsListScrollTop = 0; |
|
|
|
|
|
}); |
|
|
|
|
|
} else { |
|
|
|
|
|
// 确保吸顶状态 |
|
|
|
|
|
if (!this.isContainerSticky) { |
|
|
|
|
|
this.isContainerSticky = true; |
|
|
|
|
|
} |
|
|
|
|
|
// 通过scroll-into-view滚动到对应分类的第一个商品 |
|
|
|
|
|
const targetId = 'category-' + selectedCategory.id; |
|
|
|
|
|
// 先清空再设置,确保同一个id也能触发滚动 |
|
|
|
|
|
this.scrollIntoViewId = ''; |
|
|
|
|
|
this.$nextTick(() => { |
|
|
|
|
|
this.isAutoScrolling = true; |
|
|
|
|
|
this.scrollIntoViewId = targetId; |
|
|
|
|
|
// 延迟恢复滚动检测,避免自动滚动触发分类切换 |
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
|
this.isAutoScrolling = false; |
|
|
|
|
|
this.isSwitching = false; |
|
|
|
|
|
}, 500); |
|
|
|
|
|
}); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
|
this.isSwitching = false; |
|
|
|
|
|
}, 300); |
|
|
|
|
|
this.$forceUpdate(); |
|
|
}, |
|
|
}, |
|
|
openOrderWait(item){ |
|
|
openOrderWait(item){ |
|
|
this.chooseWaitType = false |
|
|
this.chooseWaitType = false |
|
|
@ -1221,7 +1334,6 @@ |
|
|
height: 100%; |
|
|
height: 100%; |
|
|
font-size: 24rpx; |
|
|
font-size: 24rpx; |
|
|
position: relative; |
|
|
position: relative; |
|
|
overflow: hidden; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* 顶部背景图随页面滚动(不固定) */ |
|
|
/* 顶部背景图随页面滚动(不固定) */ |
|
|
@ -1443,11 +1555,21 @@ |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.goods-list { |
|
|
.goods-list { |
|
|
width: 95%; |
|
|
flex: 1; |
|
|
height: auto; |
|
|
height: 100%; |
|
|
border-radius: 20rpx; |
|
|
border-radius: 20rpx; |
|
|
margin: 0 auto 20rpx; |
|
|
overflow: hidden; |
|
|
overflow: scroll; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.container-sticky { |
|
|
|
|
|
position: fixed; |
|
|
|
|
|
left: 0; |
|
|
|
|
|
width: 100%; |
|
|
|
|
|
z-index: 50; |
|
|
|
|
|
height: calc(100vh - 80px); |
|
|
|
|
|
background: #F5F8F5; |
|
|
|
|
|
padding: 0 2.5%; |
|
|
|
|
|
box-sizing: border-box; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.goods-top { |
|
|
.goods-top { |
|
|
|