wangfukang 4 weeks ago
parent
commit
ad24ca736f
  1. 232
      package2/group/groupBuySingle.vue

232
package2/group/groupBuySingle.vue

@ -1,6 +1,6 @@
<template> <template>
<!-- 拼团单一商家 --> <!-- 拼团单一商家 -->
<view class="page1" @touchmove="onPageTouchMove"> <view class="page1">
<!-- 固定顶部导航栏悬浮在背景图之上 --> <!-- 固定顶部导航栏悬浮在背景图之上 -->
<view class="nav-bar" <view class="nav-bar"
:style="{'padding-top': menuButtonInfo.top +'px','background':((orderListWait.length > 0 && lastScrollTop>217) || (orderListWait.length == 0 && lastScrollTop>149))?'#fff':''}"> :style="{'padding-top': menuButtonInfo.top +'px','background':((orderListWait.length > 0 && lastScrollTop>217) || (orderListWait.length == 0 && lastScrollTop>149))?'#fff':''}">
@ -111,12 +111,11 @@
</swiper-item> </swiper-item>
</swiper> </swiper>
</view> </view>
<!-- 分类栏移到goods-list外层position:sticky才能生效 --> <!-- 整页 page-scroll左侧分类条 sticky 吸顶右侧商品跟随页面滚动 -->
<!-- 占位元素当container吸顶时保持页面高度不塌缩 --> <view class="catalog-row" id="catalog-row">
<view v-if="isContainerSticky" :style="'height:' + containerHeight + 'px;margin-top:20rpx;'"></view> <view class="catalog-menu-wrap" :style="{ top: navBarHeight + 'px' }">
<view class="container goods-panel" :style="containerStyle">
<scroll-view scroll-y id="menuList" class="menu-scroll" <scroll-view scroll-y id="menuList" class="menu-scroll"
style="border-right: 1px solid #eee;font-weight: 700;font-size: 28rpx;height: 100%;width: 160rpx;"> :style="{ height: stickyInnerHeight + 'px' }">
<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-top-right-radius':item.checked?'20rpx':'','border-bottom-right-radius':item.checked?'20rpx':'','color':item.checked?'rgba(0, 35, 28, 1)':'#777','background':item.checked?'#fff':''}"> :style="{'border-top-right-radius':item.checked?'20rpx':'','border-bottom-right-radius':item.checked?'20rpx':'','color':item.checked?'rgba(0, 35, 28, 1)':'#777','background':item.checked?'#fff':''}">
<image class="menu-active-dot" v-if="item.checked" src="/static/images/img/loading.gif" <image class="menu-active-dot" v-if="item.checked" src="/static/images/img/loading.gif"
@ -124,9 +123,8 @@
<view style="width: 160rpx;">{{item.categoryName}}</view> <view style="width: 160rpx;">{{item.categoryName}}</view>
</view> </view>
</scroll-view> </scroll-view>
<scroll-view class="goods-list" scroll-y :scroll-into-view="scrollIntoViewId" </view>
:scroll-top="goodsListScrollTop" @scroll="onGoodsListScroll" @scrolltoupper="onGoodsListScrollToTop" <view class="catalog-goods">
:scroll-with-animation="true">
<view class="goods-member goods-card" :id="'category-' + item.categoryId" <view class="goods-member goods-card" :id="'category-' + item.categoryId"
v-for="(item,index) in productItem" :key="index" @tap="goDetail('product',item)"> v-for="(item,index) in productItem" :key="index" @tap="goDetail('product',item)">
<view class="goods-card-shine"></view> <view class="goods-card-shine"></view>
@ -192,8 +190,7 @@
</view> </view>
<uni-load-more :status="loadStatus" @change="onChange" /> <uni-load-more :status="loadStatus" @change="onChange" />
<view style="width: 100%;height: 160rpx;"></view> <view style="width: 100%;height: 160rpx;"></view>
</scroll-view> </view>
</view> </view>
</view> </view>
<view style="width: 100%;height: 160rpx;"></view> <view style="width: 100%;height: 160rpx;"></view>
@ -684,18 +681,11 @@
// sticky top // sticky top
navBarHeight: 0, navBarHeight: 0,
orderListWait: [], orderListWait: [],
//
menuListOffsetTop: 0,
lastScrollTop: 0, lastScrollTop: 0,
// onPageScroll // onPageScroll
isSwitching: false, isSwitching: false,
containerOriginalTop: 0, // onPageScroll data undefined
scrollIntoViewId: '', _lastDetectTs: 0,
goodsListScrollTop: 0,
isAutoScrolling: false,
isContainerSticky: false,
containerHeight: 0,
pageScrollTop: 0,
searchForm: { searchForm: {
shopId: '', shopId: '',
delFlag: 1, delFlag: 1,
@ -733,17 +723,15 @@
cartTotalPrice() { cartTotalPrice() {
return this.cartItems.reduce((acc, curr) => acc + (curr.quantity * curr.price), 0).toFixed(2); return this.cartItems.reduce((acc, curr) => acc + (curr.quantity * curr.price), 0).toFixed(2);
}, },
containerStyle() { stickyInnerHeight() {
if (this.isContainerSticky) { // sticky
// fixed = - - // iPhone
const sysInfo = uni.getSystemInfoSync(); const sysInfo = uni.getSystemInfoSync();
const bottomBarPx = Math.round(80 * sysInfo.windowWidth / 375); const safeBottom = sysInfo.safeArea ? Math.max(sysInfo.windowHeight - sysInfo.safeArea.bottom, 0) : 0;
const h = sysInfo.windowHeight - this.navBarHeight - bottomBarPx; const checkoutBarPx = Math.round(126 * sysInfo.windowWidth / 750);
return 'display:flex;position:fixed;left:0;top:' + this.navBarHeight + const checkoutOffsetPx = Math.round(18 * sysInfo.windowWidth / 750);
'px;margin:0 auto;right:0;height:' + h + 'px;z-index:50;background:#F5F8F5;box-sizing:border-box;'; const bottomReservedPx = checkoutBarPx + checkoutOffsetPx + safeBottom;
} else { return Math.max(240, sysInfo.windowHeight - this.navBarHeight - bottomReservedPx);
return 'display:flex;height:72%;margin-top:20rpx;';
}
} }
}, },
filters: { filters: {
@ -821,94 +809,74 @@
onShow() { onShow() {
this.menuButtonInfo = uni.getMenuButtonBoundingClientRect(); this.menuButtonInfo = uni.getMenuButtonBoundingClientRect();
this.fetchCoupons(); this.fetchCoupons();
// sticky offsetstatusBarHeight + 40px // (menuButton)
// / iPhone statusBarHeight + 40
const info = uni.getSystemInfoSync(); const info = uni.getSystemInfoSync();
if (this.menuButtonInfo && this.menuButtonInfo.height) {
const top = this.menuButtonInfo.top;
const padding = Math.max(top - info.statusBarHeight, 0);
this.navBarHeight = info.statusBarHeight + padding * 2 + this.menuButtonInfo.height;
} else {
this.navBarHeight = info.statusBarHeight + 40; this.navBarHeight = info.statusBarHeight + 40;
}
}, },
onPullDownRefresh() { onPullDownRefresh() {
this.getCategory(this.shopItem.id); this.getCategory(this.shopItem.id);
this.getProduct(''); this.getProduct('');
}, },
onReady() { onReady() {
// container
setTimeout(() => {
const query = uni.createSelectorQuery().in(this);
query.select('.container').boundingClientRect(rect => {
if (rect) {
this.containerOriginalTop = rect.top;
this.menuListOffsetTop = rect.top;
this.containerHeight = rect.height;
}
}).exec();
}, 500);
}, },
onPageScroll(e) { onPageScroll(e) {
this.lastScrollTop = e.scrollTop; this.lastScrollTop = e.scrollTop;
// container // 80ms selectorQuery
const stickyThreshold = this.containerOriginalTop - this.navBarHeight; const now = Date.now();
if (stickyThreshold <= 0) return; if (now - this._lastDetectTs < 80) return;
if (e.scrollTop >= stickyThreshold) { this._lastDetectTs = now;
if (!this.isContainerSticky) { this.detectCurrentCategory();
this.isContainerSticky = true;
}
//
if (e.scrollTop > stickyThreshold + 5) {
uni.pageScrollTo({
scrollTop: stickyThreshold,
duration: 0
});
}
} else {
if (this.isContainerSticky) {
this.isContainerSticky = false;
}
}
}, },
methods: { methods: {
nowMakeMethod(){ nowMakeMethod(){
this.nowMake = !this.nowMake this.nowMake = !this.nowMake
}, },
// touchmovegoods-list scrollGoodsListToTop() {
onPageTouchMove(e) { // catalog-row nav-bar
const query = uni.createSelectorQuery().in(this);
}, query.select('#catalog-row').boundingClientRect();
// goods-list + query.selectViewport().scrollOffset();
onGoodsListScroll(e) { query.exec((res) => {
if (this.isAutoScrolling) return; if (!res || !res[0] || !res[1]) {
const scrollTop = e.detail.scrollTop; this.isSwitching = false;
return;
// }
this.detectCurrentCategory(); const target = Math.max(res[1].scrollTop + res[0].top - this.navBarHeight, 0);
}, uni.pageScrollTo({
onGoodsListScrollToTop() { scrollTop: target,
if (this.isAutoScrolling) return; duration: 200
});
setTimeout(() => {
this.isSwitching = false;
}, 350);
});
}, },
// // nav-bar 沿
detectCurrentCategory() { detectCurrentCategory() {
if (this.isSwitching) return; if (this.isSwitching) return;
const query = uni.createSelectorQuery().in(this); const query = uni.createSelectorQuery().in(this);
// goods-listgoods-member
query.selectAll('.goods-member').boundingClientRect(); query.selectAll('.goods-member').boundingClientRect();
query.select('.goods-list').boundingClientRect();
query.exec((res) => { query.exec((res) => {
if (!res || !res[0] || !res[1]) return; if (!res || !res[0]) return;
const items = res[0]; const items = res[0];
const listRect = res[1]; // navBarHeight
const listTop = listRect.top; const baseline = this.navBarHeight + 20;
let currentCategoryId = ''; let currentCategoryId = '';
// goods-listitem
for (let i = items.length - 1; i >= 0; i--) { for (let i = items.length - 1; i >= 0; i--) {
if (items[i].top <= listTop + 10) { if (items[i].top <= baseline) {
// productItemcategoryId
if (this.productItem[i]) { if (this.productItem[i]) {
currentCategoryId = this.productItem[i].categoryId; currentCategoryId = this.productItem[i].categoryId;
} }
break; break;
} }
} }
if (currentCategoryId !== '' || currentCategoryId === '') {
// menuList
let found = false; let found = false;
for (let i = 0; i < this.menuList.length; i++) { for (let i = 0; i < this.menuList.length; i++) {
if (String(this.menuList[i].id) === String(currentCategoryId)) { if (String(this.menuList[i].id) === String(currentCategoryId)) {
@ -916,19 +884,15 @@
for (let j = 0; j < this.menuList.length; j++) { for (let j = 0; j < this.menuList.length; j++) {
this.menuList[j].checked = (j === i); this.menuList[j].checked = (j === i);
} }
this.$forceUpdate();
} }
found = true; found = true;
break; break;
} }
} }
// categoryId""
if (!found && currentCategoryId === '') { if (!found && currentCategoryId === '') {
for (let j = 0; j < this.menuList.length; j++) { for (let j = 0; j < this.menuList.length; j++) {
this.menuList[j].checked = (j === 0); this.menuList[j].checked = (j === 0);
} }
this.$forceUpdate();
}
} }
}); });
}, },
@ -1014,49 +978,34 @@
} }
const selectedCategory = this.menuList[index]; const selectedCategory = this.menuList[index];
// ""idtuijian
if (!selectedCategory.id && selectedCategory.id !== 0) { if (!selectedCategory.id && selectedCategory.id !== 0) {
this.goodsListScrollTop = 0; this.scrollGoodsListToTop();
this.$nextTick(() => {
this.goodsListScrollTop = 0;
});
setTimeout(() => {
this.isSwitching = false;
}, 300);
this.$forceUpdate();
return; return;
} }
// // scroll #category-<id> nav-bar 沿
const doScrollToCategory = () => { const targetSelector = '#category-' + selectedCategory.id;
const targetId = 'category-' + selectedCategory.id;
this.scrollIntoViewId = '';
this.$nextTick(() => { this.$nextTick(() => {
this.isAutoScrolling = true; const query = uni.createSelectorQuery().in(this);
this.scrollIntoViewId = targetId; query.select(targetSelector).boundingClientRect();
setTimeout(() => { query.selectViewport().scrollOffset();
this.isAutoScrolling = false; query.exec((res) => {
if (!res || !res[0] || !res[1]) {
this.isSwitching = false; this.isSwitching = false;
}, 500); return;
}); }
}; const rect = res[0];
const vp = res[1];
// const target = Math.max(vp.scrollTop + rect.top - this.navBarHeight, 0);
if (!this.isContainerSticky) {
const stickyThreshold = this.containerOriginalTop - this.navBarHeight;
uni.pageScrollTo({ uni.pageScrollTo({
scrollTop: stickyThreshold, scrollTop: target,
duration: 200, duration: 200
complete: () => { });
setTimeout(() => { setTimeout(() => {
doScrollToCategory(); this.isSwitching = false;
}, 250); }, 350);
} });
}); });
} else {
doScrollToCategory();
}
this.$forceUpdate();
}, },
openOrderWait(item) { openOrderWait(item) {
this.chooseWaitType = false this.chooseWaitType = false
@ -2051,8 +2000,9 @@
.goods-list { .goods-list {
flex: 1; flex: 1;
height: 100%; min-height: 0;
border-radius: 20rpx; border-radius: 20rpx;
overflow: hidden;
} }
.fee-value { .fee-value {
color: #00231C; color: #00231C;
@ -2805,9 +2755,37 @@
box-shadow: 0 -8rpx 28rpx rgba(0, 35, 28, 0.04); box-shadow: 0 -8rpx 28rpx rgba(0, 35, 28, 0.04);
} }
/* 单一 page-scroll 结构下的目录布局:左侧分类条 sticky,右侧商品跟随页面滚动 */
.catalog-row {
display: flex;
align-items: flex-start;
margin-top: 20rpx;
background: transparent;
}
.catalog-menu-wrap {
position: sticky;
z-index: 50;
flex-shrink: 0;
width: 160rpx;
background: rgba(247, 255, 251, 0.95);
border-right: 1rpx solid #eee;
border-top-left-radius: 34rpx;
}
.catalog-goods {
flex: 1;
min-width: 0;
padding-left: 4rpx;
}
.menu-scroll { .menu-scroll {
background: rgba(247, 255, 251, 0.9); background: rgba(247, 255, 251, 0.9);
border-right: 0 !important; border-right: 0 !important;
flex-shrink: 0;
width: 160rpx;
font-weight: 700;
font-size: 28rpx;
} }
.menu1 { .menu1 {

Loading…
Cancel
Save