首页底部
Test Runner / hello (push) Successful in 4s

This commit is contained in:
2026-08-25 18:12:16 +08:00
parent 69734f36b4
commit 4bee0101e7
22 changed files with 378 additions and 183 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+105 -84
View File
@@ -188,6 +188,16 @@ var _default = {
ProductGrid: ProductGrid,
FilterDrawer: FilterDrawer
},
watch: {
// 筛选标签增减 → 子组件会自测量并 emit,父组件这里不需要 watch
// 保留一个兜底:activeFilters.length 变化时主动触发一次重算
'activeFilters.length': function activeFiltersLength() {
this.recomputeScrollHeight();
},
'subCategories.length': function subCategoriesLength() {
this.recomputeScrollHeight();
}
},
data: function data() {
return {
searchKeyword: '',
@@ -213,21 +223,29 @@ var _default = {
products: [],
windowHeight: 667,
scrollTopVal: 0,
productScrollHeight: 400 // 商品滚动区高度(px),动态计算
productScrollHeight: 400,
// 商品滚动区高度(px),由子组件测量后动态计算
// 各子组件上报的高度(px),默认 0
_searchBarH: 0,
_countryBarH: 0,
_activeFiltersH: 0,
_subCategoriesH: 0
};
},
onLoad: function onLoad() {
var _this = this;
return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
var sysInfo;
var sysInfo, tabBarHeight;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
try {
sysInfo = uni.getSystemInfoSync(); // windowHeight 已自动扣除 uni-app 默认导航栏 & TabBar 高度
// 当前页是 navigationStyle:custom + TabBar 页,正好匹配可视区
_this.windowHeight = sysInfo.windowHeight || 667;
sysInfo = uni.getSystemInfoSync(); // tabBar 页 + navigationStyle:custom 时,windowHeight 在不同平台/版本可能不扣 tabBar
// 改用 screenHeight - tabBarHeight 计算,确保可视区高度正确
tabBarHeight = sysInfo.tabBarHeight || 50;
_this.windowHeight = (sysInfo.screenHeight || 750) - tabBarHeight;
console.log('[onLoad] screenHeight=' + sysInfo.screenHeight + ', tabBarHeight=' + tabBarHeight + ' → windowHeight=' + _this.windowHeight);
} catch (e) {
_this.windowHeight = 667;
}
@@ -238,10 +256,9 @@ var _default = {
_context.next = 6;
return _this.loadGoods(1);
case 6:
// 首屏数据渲染完成后计算滚动区高度
_this.$nextTick(function () {
_this.calcScrollHeight();
});
// 首屏数据渲染完成后,子组件会通过 mounted 自行测量并 emit 高度
// 这里兜底触发一次重算(防止某些端 mounted 比父组件 onLoad 晚)
_this.recomputeScrollHeight();
case 7:
case "end":
return _context.stop();
@@ -432,10 +449,8 @@ var _default = {
_this4.hasMore = _this4.products.length < total;
_this4.loadingMore = false;
// 数据变更后重算滚动区高度(筛选标签/子分类数量变化会影响上方占位高度
_this4.$nextTick(function () {
_this4.calcScrollHeight();
});
// 数据变更后兜底重算滚动区高度(子组件会自行 emit,这里兜底
_this4.recomputeScrollHeight();
console.log('[loadGoods] total=' + total + ', page=' + currentPage + ', items=' + products.length + ', loaded=' + _this4.products.length + ', hasMore=' + _this4.hasMore);
_context4.next = 25;
break;
@@ -542,64 +557,70 @@ var _default = {
});
},
/**
* 动态计算商品滚动区高度(px)。
* 用 createSelectorQuery 测量 SearchBar / CountryBar / ActiveFilters / subCategories 的实际高度
* 用 windowHeight 依次减去,得到 scroll-view 可用的固定高度。
* 子组件高度上报回调 —— 每个子组件在 mounted / 内容变化时自行测量 DOM 高度,
* 通过 @height-change 事件上报给父组件。父组件汇总后重算滚动区高度
*
* 这种方式解决了 uni-app 小程序端 createSelectorQuery 无法跨组件查询 DOM 的问题:
* H5 端 DOM 全局可查,但小程序每个组件有独立节点树,页面级 select 选不到子组件内部的节点。
*/
onSearchBarHeight: function onSearchBarHeight(h) {
this._searchBarH = h;
this.recomputeScrollHeight();
},
onCountryBarHeight: function onCountryBarHeight(h) {
this._countryBarH = h;
this.recomputeScrollHeight();
},
onActiveFiltersHeight: function onActiveFiltersHeight(h) {
this._activeFiltersH = h;
this.recomputeScrollHeight();
},
onSubCategoriesHeight: function onSubCategoriesHeight(h) {
this._subCategoriesH = h;
this.recomputeScrollHeight();
},
/**
* 根据 4 个子组件上报的高度,计算 scroll-view 可用的固定高度。
* —— 完全符合 uni-app / 微信小程序官方文档「scroll-y 需给固定 height」的要求。
*/
calcScrollHeight: function calcScrollHeight() {
var _this6 = this;
var 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(function (res) {
// res[0]=searchBar, res[1]=countryBar, res[2]=activeFilters, res[3]=subCategories
// 注意:v-if 为 false 时 res[i] 可能为 null
var searchBarH = res[0] ? res[0].height : 0;
var countryBarH = res[1] ? res[1].height : 0;
var activeFiltersH = res[2] ? res[2].height : 0;
var subCategoriesH = res[3] ? res[3].height : 0;
var totalUsed = searchBarH + countryBarH + activeFiltersH + subCategoriesH;
var h = _this6.windowHeight - totalUsed;
// 最小值保护:至少 200px,避免极端情况
if (h < 200) h = 200;
if (h > _this6.windowHeight) h = _this6.windowHeight;
_this6.productScrollHeight = Math.round(h);
console.log('[calcScrollHeight] windowHeight=' + _this6.windowHeight + ', searchBar=' + searchBarH + ', countryBar=' + countryBarH + ', activeFilters=' + activeFiltersH + ', subCategories=' + subCategoriesH + ' → scrollHeight=' + _this6.productScrollHeight);
});
recomputeScrollHeight: function recomputeScrollHeight() {
var totalUsed = this._searchBarH + this._countryBarH + this._activeFiltersH + this._subCategoriesH;
var h = this.windowHeight - totalUsed;
// 最小值保护:至少 200px,避免极端情况
if (h < 200) h = 200;
if (h > this.windowHeight) h = this.windowHeight;
this.productScrollHeight = Math.round(h);
console.log('[recomputeScrollHeight] windowHeight=' + this.windowHeight + ', searchBar=' + this._searchBarH + ', countryBar=' + this._countryBarH + ', activeFilters=' + this._activeFiltersH + ', subCategories=' + this._subCategoriesH + ' → scrollHeight=' + this.productScrollHeight);
},
selectCountry: function selectCountry(id) {
var _this7 = this;
var _this6 = this;
return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5() {
var country, filters;
return _regenerator.default.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
if (!(_this7.selectedCountry === id)) {
if (!(_this6.selectedCountry === id)) {
_context5.next = 8;
break;
}
_this7.selectedCountry = '';
_this7.activeFilters = _this7.activeFilters.filter(function (f) {
_this6.selectedCountry = '';
_this6.activeFilters = _this6.activeFilters.filter(function (f) {
return f.key !== 'country';
});
_context5.next = 5;
return _this7.loadCategoryData('');
return _this6.loadCategoryData('');
case 5:
_context5.next = 7;
return _this7.loadGoods(1);
return _this6.loadGoods(1);
case 7:
return _context5.abrupt("return");
case 8:
// 选中新国家
country = _this7.countries.find(function (c) {
country = _this6.countries.find(function (c) {
return c.id === id;
});
filters = _this7.activeFilters.filter(function (f) {
filters = _this6.activeFilters.filter(function (f) {
return f.key !== 'country';
});
if (country) {
@@ -608,13 +629,13 @@ var _default = {
label: country.name
});
}
_this7.selectedCountry = id;
_this7.activeFilters = filters;
_this6.selectedCountry = id;
_this6.activeFilters = filters;
_context5.next = 15;
return _this7.loadCategoryData(id);
return _this6.loadCategoryData(id);
case 15:
_context5.next = 17;
return _this7.loadGoods(1);
return _this6.loadGoods(1);
case 17:
case "end":
return _context5.stop();
@@ -624,16 +645,16 @@ var _default = {
}))();
},
selectCategory: function selectCategory(id) {
var _this8 = this;
var _this7 = this;
return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee6() {
return _regenerator.default.wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
_this8.activeCategory = id;
_this8.loadSubCategories(id);
_this7.activeCategory = id;
_this7.loadSubCategories(id);
_context6.next = 4;
return _this8.loadGoods(1);
return _this7.loadGoods(1);
case 4:
case "end":
return _context6.stop();
@@ -643,15 +664,15 @@ var _default = {
}))();
},
selectSubCategory: function selectSubCategory(id) {
var _this9 = this;
var _this8 = this;
return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee7() {
return _regenerator.default.wrap(function _callee7$(_context7) {
while (1) {
switch (_context7.prev = _context7.next) {
case 0:
_this9.activeSubCategory = id;
_this8.activeSubCategory = id;
_context7.next = 3;
return _this9.loadGoods(1);
return _this8.loadGoods(1);
case 3:
case "end":
return _context7.stop();
@@ -683,27 +704,27 @@ var _default = {
this.filterGroups = groups;
},
removeFilter: function removeFilter(key) {
var _this10 = this;
var _this9 = this;
return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee8() {
var filters, groupId, groups;
return _regenerator.default.wrap(function _callee8$(_context8) {
while (1) {
switch (_context8.prev = _context8.next) {
case 0:
filters = _this10.activeFilters.filter(function (f) {
filters = _this9.activeFilters.filter(function (f) {
return f.key !== key;
});
if (!(key === 'country')) {
_context8.next = 9;
break;
}
_this10.selectedCountry = '';
_this10.activeFilters = filters;
_this9.selectedCountry = '';
_this9.activeFilters = filters;
_context8.next = 6;
return _this10.loadCategoryData('');
return _this9.loadCategoryData('');
case 6:
_context8.next = 8;
return _this10.loadGoods(1);
return _this9.loadGoods(1);
case 8:
return _context8.abrupt("return");
case 9:
@@ -712,7 +733,7 @@ var _default = {
break;
}
groupId = key.replace('tag_', '');
groups = _this10.filterGroups.map(function (g) {
groups = _this9.filterGroups.map(function (g) {
if (String(g.id) === String(groupId)) {
return Object.assign({}, g, {
selected: []
@@ -720,14 +741,14 @@ var _default = {
}
return g;
});
_this10.activeFilters = filters;
_this10.filterGroups = groups;
_this9.activeFilters = filters;
_this9.filterGroups = groups;
_context8.next = 16;
return _this10.loadGoods(1);
return _this9.loadGoods(1);
case 16:
return _context8.abrupt("return");
case 17:
_this10.activeFilters = filters;
_this9.activeFilters = filters;
case 18:
case "end":
return _context8.stop();
@@ -737,33 +758,33 @@ var _default = {
}))();
},
clearAllFilters: function clearAllFilters() {
var _this11 = this;
var _this10 = this;
return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee9() {
var hasCountry, groups;
return _regenerator.default.wrap(function _callee9$(_context9) {
while (1) {
switch (_context9.prev = _context9.next) {
case 0:
hasCountry = _this11.activeFilters.some(function (f) {
hasCountry = _this10.activeFilters.some(function (f) {
return f.key === 'country';
});
_this11.activeFilters = [];
if (!(hasCountry || _this11.selectedCountry)) {
_this10.activeFilters = [];
if (!(hasCountry || _this10.selectedCountry)) {
_context9.next = 6;
break;
}
_this11.selectedCountry = '';
_this10.selectedCountry = '';
_context9.next = 6;
return _this11.loadCategoryData('');
return _this10.loadCategoryData('');
case 6:
groups = _this11.filterGroups.map(function (g) {
groups = _this10.filterGroups.map(function (g) {
return Object.assign({}, g, {
selected: []
});
});
_this11.filterGroups = groups;
_this10.filterGroups = groups;
_context9.next = 10;
return _this11.loadGoods(1);
return _this10.loadGoods(1);
case 10:
case "end":
return _context9.stop();
@@ -781,7 +802,7 @@ var _default = {
this.filterGroups = groups;
},
confirmFilters: function confirmFilters() {
var _this12 = this;
var _this11 = this;
return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee10() {
var filters, countryFilter;
return _regenerator.default.wrap(function _callee10$(_context10) {
@@ -789,11 +810,11 @@ var _default = {
switch (_context10.prev = _context10.next) {
case 0:
filters = [];
countryFilter = _this12.activeFilters.find(function (f) {
countryFilter = _this11.activeFilters.find(function (f) {
return f.key === 'country';
});
if (countryFilter) filters.push(countryFilter);
_this12.filterGroups.forEach(function (group) {
_this11.filterGroups.forEach(function (group) {
if (group.selected.length > 0) {
var labels = group.tags.filter(function (t) {
return group.selected.indexOf(t.id) > -1;
@@ -808,10 +829,10 @@ var _default = {
}
}
});
_this12.activeFilters = filters;
_this12.showFilter = false;
_this11.activeFilters = filters;
_this11.showFilter = false;
_context10.next = 8;
return _this12.loadGoods(1);
return _this11.loadGoods(1);
case 8:
case "end":
return _context10.stop();
+1 -1
View File
@@ -1 +1 @@
<view class="products-page" style="{{'height:'+(windowHeight+'px')+';'}}"><search-bar vue-id="08007ac0-1" keyword="{{searchKeyword}}" data-event-opts="{{[['^input',[['onSearchInput']]],['^blur',[['onSearchBlur']]],['^filter',[['toggleFilter']]]]}}" bind:input="__e" bind:blur="__e" bind:filter="__e" bind:__l="__l"></search-bar><country-bar vue-id="08007ac0-2" list="{{countries}}" selected-id="{{selectedCountry}}" data-event-opts="{{[['^select',[['selectCountry']]]]}}" bind:select="__e" bind:__l="__l"></country-bar><view class="content-body"><category-sidebar vue-id="08007ac0-3" list="{{categories}}" active-id="{{activeCategory}}" data-event-opts="{{[['^select',[['selectCategory']]]]}}" bind:select="__e" bind:__l="__l"></category-sidebar><view class="right-wrap"><active-filters vue-id="08007ac0-4" list="{{activeFilters}}" data-event-opts="{{[['^remove',[['removeFilter']]],['^clearAll',[['clearAllFilters']]]]}}" bind:remove="__e" bind:clearAll="__e" bind:__l="__l"></active-filters><product-grid vue-id="08007ac0-5" list="{{products}}" sub-categories="{{subCategories}}" active-sub-id="{{activeSubCategory}}" has-more="{{hasMore}}" loading="{{loadingMore}}" scroll-top-val="{{scrollTopVal}}" scroll-height="{{productScrollHeight}}" data-event-opts="{{[['^subSelect',[['selectSubCategory']]],['^productClick',[['goDetail']]],['^scrollToLower',[['onScrollToLower']]]]}}" bind:subSelect="__e" bind:productClick="__e" bind:scrollToLower="__e" bind:__l="__l"></product-grid></view></view><filter-drawer vue-id="08007ac0-6" visible="{{showFilter}}" groups="{{filterGroups}}" data-event-opts="{{[['^close',[['closeFilter']]],['^toggleTag',[['toggleFilterTag']]],['^reset',[['resetFilters']]],['^confirm',[['confirmFilters']]]]}}" bind:close="__e" bind:toggleTag="__e" bind:reset="__e" bind:confirm="__e" bind:__l="__l"></filter-drawer></view>
<view class="products-page" style="{{'height:'+(windowHeight+'px')+';'}}"><search-bar vue-id="08007ac0-1" keyword="{{searchKeyword}}" data-event-opts="{{[['^input',[['onSearchInput']]],['^blur',[['onSearchBlur']]],['^filter',[['toggleFilter']]],['^heightChange',[['onSearchBarHeight']]]]}}" bind:input="__e" bind:blur="__e" bind:filter="__e" bind:heightChange="__e" bind:__l="__l"></search-bar><country-bar vue-id="08007ac0-2" list="{{countries}}" selected-id="{{selectedCountry}}" data-event-opts="{{[['^select',[['selectCountry']]],['^heightChange',[['onCountryBarHeight']]]]}}" bind:select="__e" bind:heightChange="__e" bind:__l="__l"></country-bar><view class="content-body"><category-sidebar vue-id="08007ac0-3" list="{{categories}}" active-id="{{activeCategory}}" data-event-opts="{{[['^select',[['selectCategory']]]]}}" bind:select="__e" bind:__l="__l"></category-sidebar><view class="right-wrap"><active-filters vue-id="08007ac0-4" list="{{activeFilters}}" data-event-opts="{{[['^remove',[['removeFilter']]],['^clearAll',[['clearAllFilters']]],['^heightChange',[['onActiveFiltersHeight']]]]}}" bind:remove="__e" bind:clearAll="__e" bind:heightChange="__e" bind:__l="__l"></active-filters><product-grid vue-id="08007ac0-5" list="{{products}}" sub-categories="{{subCategories}}" active-sub-id="{{activeSubCategory}}" has-more="{{hasMore}}" loading="{{loadingMore}}" scroll-top-val="{{scrollTopVal}}" scroll-height="{{productScrollHeight}}" data-event-opts="{{[['^subSelect',[['selectSubCategory']]],['^productClick',[['goDetail']]],['^scrollToLower',[['onScrollToLower']]],['^subHeightChange',[['onSubCategoriesHeight']]]]}}" bind:subSelect="__e" bind:productClick="__e" bind:scrollToLower="__e" bind:subHeightChange="__e" bind:__l="__l"></product-grid></view></view><filter-drawer vue-id="08007ac0-6" visible="{{showFilter}}" groups="{{filterGroups}}" data-event-opts="{{[['^close',[['closeFilter']]],['^toggleTag',[['toggleFilterTag']]],['^reset',[['resetFilters']]],['^confirm',[['confirmFilters']]]]}}" bind:close="__e" bind:toggleTag="__e" bind:reset="__e" bind:confirm="__e" bind:__l="__l"></filter-drawer></view>