修复商品列表滚动错误
Test Runner / hello (push) Failing after 32s

This commit is contained in:
2026-08-25 14:25:43 +08:00
parent 65356953ed
commit 69734f36b4
25 changed files with 642 additions and 246 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
<template>
<!-- 已选筛选标签 - Figma 1519:250 圆角 60px -->
<view class="active-filters" v-if="list.length > 0">
<view class="active-filters" id="activeFilters" v-if="list.length > 0">
<view class="active-filter-tag" v-for="(item, index) in list" :key="index">
<text class="filter-text">{{ item.label }}</text>
<text class="filter-remove" @tap="onRemove(item.key)">×</text>
+1 -1
View File
@@ -1,6 +1,6 @@
<template>
<!-- 国家选择条 - 换行布局(对应 Figma 1511:195) -->
<view class="country-bar">
<view class="country-bar" id="countryBar">
<view class="country-inner">
<view
class="country-item"
+18 -15
View File
@@ -2,7 +2,7 @@
<!-- 右侧商品列表区 - 上方子分类 + 下方滚动商品网格 -->
<view class="right-content">
<!-- 子分类(顶部条件) - Figma 1519:250 -->
<view class="sub-categories" v-if="subCategories.length > 0">
<view class="sub-categories" id="subCategories" v-if="subCategories.length > 0">
<view
class="sub-cat-item"
:class="{ active: activeSubId === item.id }"
@@ -12,8 +12,16 @@
>{{ item.name }}</view>
</view>
<!-- 商品网格滚动区 -->
<scroll-view scroll-y class="product-scroll" :lower-threshold="100" :scroll-top="scrollTopVal" :scroll-with-animation="false" @scrolltolower="onScrollToLower">
<!-- 商品网格滚动区 - 固定高度由父组件动态计算传入符合官方文档要求 -->
<scroll-view
scroll-y
class="product-scroll"
:lower-threshold="100"
:scroll-top="scrollTopVal"
:scroll-with-animation="false"
:style="{ height: scrollHeight + 'px' }"
@scrolltolower="onScrollToLower"
>
<view class="product-grid" v-if="list.length > 0">
<view
class="product-card"
@@ -69,7 +77,9 @@ export default {
activeSubId: { type: [String, Number], default: '' },
hasMore: { type: Boolean, default: true },
loading: { type: Boolean, default: false },
scrollTopVal: { type: Number, default: 0 }
scrollTopVal: { type: Number, default: 0 },
// 商品滚动区固定高度(px),由父组件动态计算传入
scrollHeight: { type: Number, default: 400 }
},
methods: {
selectSub(id) { this.$emit('sub-select', id) },
@@ -81,15 +91,11 @@ export default {
<style scoped>
/* 右侧内容区 - 上下分:顶部条件 + 下方滚动
flex:1 与 height:100% 冲突,二选一(保留 flex:1) */
不再依赖 flex:1 撑高度,scroll-view 用父组件传入的固定高度 */
.right-content {
flex: 1;
min-width: 0;
min-height: 0;
display: flex;
flex-direction: column;
background: #f2f2f2;
overflow: hidden;
}
/* 顶部子分类条件 - padding 6px 10px 圆角 60px */
@@ -116,13 +122,10 @@ export default {
color: #ff6800;
}
/* 滚动商品区 - uni-app scroll-view 在 flex 布局里必须同时有 flex:1 + height:0
仅 min-height:0 无法让部分端的 scroll-view 正确计算内部 viewport 高度 */
/* 滚动商品区 - 高度由父组件通过 :style 传入(px 固定值),
符合 uni-app / 微信小程序官方文档「scroll-y 需给固定 height」的要求 */
.product-scroll {
flex: 1;
height: 0;
min-height: 0;
overflow: hidden;
width: 100%;
}
/* 商品网格 - 固定2列 grid,不会因商品个数变化而拉伸占行 */
+1 -1
View File
@@ -1,6 +1,6 @@
<template>
<!-- 搜索栏 -->
<view class="search-bar" :style="{ paddingTop: statusBarHeight + 'px' }">
<view class="search-bar" id="searchBar" :style="{ paddingTop: statusBarHeight + 'px' }">
<view class="search-input-wrap">
<text class="search-icon">🔍</text>
<input
+47 -1
View File
@@ -42,6 +42,7 @@
:has-more="hasMore"
:loading="loadingMore"
:scroll-top-val="scrollTopVal"
:scroll-height="productScrollHeight"
@sub-select="selectSubCategory"
@product-click="goDetail"
@scroll-to-lower="onScrollToLower"
@@ -108,7 +109,8 @@ export default {
loadingMore: false,
products: [],
windowHeight: 667,
scrollTopVal: 0
scrollTopVal: 0,
productScrollHeight: 400 // 商品滚动区高度(px),动态计算
}
},
async onLoad() {
@@ -123,6 +125,10 @@ export default {
await this.initData()
this.loadSubCategories('all')
await this.loadGoods(1)
// 首屏数据渲染完成后计算滚动区高度
this.$nextTick(() => {
this.calcScrollHeight()
})
},
methods: {
async initData() {
@@ -253,6 +259,11 @@ export default {
this.hasMore = this.products.length < total
this.loadingMore = false
// 数据变更后重算滚动区高度(筛选标签/子分类数量变化会影响上方占位高度)
this.$nextTick(() => {
this.calcScrollHeight()
})
console.log(
'[loadGoods] total=' + total +
', page=' + currentPage +
@@ -352,6 +363,41 @@ export default {
})
},
/**
* 动态计算商品滚动区高度(px)。
* 用 createSelectorQuery 测量 SearchBar / CountryBar / ActiveFilters / subCategories 的实际高度,
* 用 windowHeight 依次减去,得到 scroll-view 可用的固定高度。
* —— 完全符合 uni-app / 微信小程序官方文档「scroll-y 需给固定 height」的要求。
*/
calcScrollHeight() {
const query = uni.createSelectorQuery().in(this)
// 分别测量 4 个元素的 boundingClientRect
query.select('#searchBar').boundingClientRect()
query.select('#countryBar').boundingClientRect()
query.select('#activeFilters').boundingClientRect()
query.select('#subCategories').boundingClientRect()
query.exec((res) => {
// res[0]=searchBar, res[1]=countryBar, res[2]=activeFilters, res[3]=subCategories
// 注意:v-if 为 false 时 res[i] 可能为 null
const searchBarH = res[0] ? res[0].height : 0
const countryBarH = res[1] ? res[1].height : 0
const activeFiltersH = res[2] ? res[2].height : 0
const subCategoriesH = res[3] ? res[3].height : 0
const totalUsed = searchBarH + countryBarH + activeFiltersH + subCategoriesH
let h = this.windowHeight - totalUsed
// 最小值保护:至少 200px,避免极端情况
if (h < 200) h = 200
if (h > this.windowHeight) h = this.windowHeight
this.productScrollHeight = Math.round(h)
console.log('[calcScrollHeight] windowHeight=' + this.windowHeight +
', searchBar=' + searchBarH + ', countryBar=' + countryBarH +
', activeFilters=' + activeFiltersH + ', subCategories=' + subCategoriesH +
' → scrollHeight=' + this.productScrollHeight)
})
},
async selectCountry(id) {
// 如果点击的是已选中的国家 → 取消选中
if (this.selectedCountry === id) {