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

336
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,22 +111,20 @@
</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="{ height: stickyInnerHeight + 'px' }">
style="border-right: 1px solid #eee;font-weight: 700;font-size: 28rpx;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-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" mode="aspectFit"></image>
mode="aspectFit"></image> <view style="width: 160rpx;">{{item.categoryName}}</view>
<view style="width: 160rpx;">{{item.categoryName}}</view> </view>
</view> </scroll-view>
</scroll-view> </view>
<scroll-view class="goods-list" scroll-y :scroll-into-view="scrollIntoViewId" <view class="catalog-goods">
:scroll-top="goodsListScrollTop" @scroll="onGoodsListScroll" @scrolltoupper="onGoodsListScrollToTop"
: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>
@ -681,21 +678,14 @@
pageNum: 1, pageNum: 1,
total: 1, total: 1,
chooseWaitType: false, chooseWaitType: false,
// sticky top // sticky top
navBarHeight: 0, navBarHeight: 0,
orderListWait: [], orderListWait: [],
// lastScrollTop: 0,
menuListOffsetTop: 0, // onPageScroll
lastScrollTop: 0, isSwitching: false,
// onPageScroll // onPageScroll data undefined
isSwitching: false, _lastDetectTs: 0,
containerOriginalTop: 0,
scrollIntoViewId: '',
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,113 +809,89 @@
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();
this.navBarHeight = info.statusBarHeight + 40; 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;
}
}, },
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 === '') { let found = false;
// menuList for (let i = 0; i < this.menuList.length; i++) {
let found = false; if (String(this.menuList[i].id) === String(currentCategoryId)) {
for (let i = 0; i < this.menuList.length; i++) { if (!this.menuList[i].checked) {
if (String(this.menuList[i].id) === String(currentCategoryId)) { for (let j = 0; j < this.menuList.length; j++) {
if (!this.menuList[i].checked) { this.menuList[j].checked = (j === i);
for (let j = 0; j < this.menuList.length; j++) {
this.menuList[j].checked = (j === i);
}
this.$forceUpdate();
} }
found = true;
break;
} }
found = true;
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();
} }
} }
}); });
@ -977,9 +941,9 @@
// //
that.getOrderWait(); that.getOrderWait();
that.total = res.result.pages; // pages = that.total = res.result.pages; // pages =
that.pageNum = that.searchForm.pageNum; that.pageNum = that.searchForm.pageNum;
that.$forceUpdate(); that.$forceUpdate();
} else { } else {
that.tui.toast(res.message, 1000); that.tui.toast(res.message, 1000);
return; return;
@ -1007,57 +971,42 @@
uni.hideLoading() uni.hideLoading()
}).catch((res) => {}) }).catch((res) => {})
}, },
checkTab(index) { checkTab(index) {
this.isSwitching = true; 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];
// ""idtuijian
if (!selectedCategory.id && selectedCategory.id !== 0) {
this.goodsListScrollTop = 0;
this.$nextTick(() => {
this.goodsListScrollTop = 0;
});
setTimeout(() => {
this.isSwitching = false;
}, 300);
this.$forceUpdate();
return;
}
// const selectedCategory = this.menuList[index];
const doScrollToCategory = () => { if (!selectedCategory.id && selectedCategory.id !== 0) {
const targetId = 'category-' + selectedCategory.id; this.scrollGoodsListToTop();
this.scrollIntoViewId = ''; return;
this.$nextTick(() => { }
this.isAutoScrolling = true;
this.scrollIntoViewId = targetId;
setTimeout(() => {
this.isAutoScrolling = false;
this.isSwitching = false;
}, 500);
});
};
// // scroll #category-<id> nav-bar 沿
if (!this.isContainerSticky) { const targetSelector = '#category-' + selectedCategory.id;
const stickyThreshold = this.containerOriginalTop - this.navBarHeight; this.$nextTick(() => {
const query = uni.createSelectorQuery().in(this);
query.select(targetSelector).boundingClientRect();
query.selectViewport().scrollOffset();
query.exec((res) => {
if (!res || !res[0] || !res[1]) {
this.isSwitching = false;
return;
}
const rect = res[0];
const vp = res[1];
const target = Math.max(vp.scrollTop + rect.top - this.navBarHeight, 0);
uni.pageScrollTo({ uni.pageScrollTo({
scrollTop: stickyThreshold, scrollTop: target,
duration: 200, duration: 200
complete: () => {
setTimeout(() => {
doScrollToCategory();
}, 250);
}
}); });
} else { setTimeout(() => {
doScrollToCategory(); this.isSwitching = false;
} }, 350);
this.$forceUpdate(); });
}, });
},
openOrderWait(item) { openOrderWait(item) {
this.chooseWaitType = false this.chooseWaitType = false
if (item != '') { if (item != '') {
@ -1175,15 +1124,15 @@
} }
} }
that.$forceUpdate(); that.$forceUpdate();
} else { } else {
that.tui.toast(res.message, 1000); that.tui.toast(res.message, 1000);
return; return;
} }
uni.hideLoading(); uni.hideLoading();
}).catch((res) => {}); }).catch((res) => {});
}, },
chooseOrderWait(item) { chooseOrderWait(item) {
this.$refs.pintuanGroupPopup.close(); this.$refs.pintuanGroupPopup.close();
this.isPindan = true; this.isPindan = true;
this.$refs.tishiPopup.open(); this.$refs.tishiPopup.open();
@ -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