File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+105
-84
@@ -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 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>
|
||||
Reference in New Issue
Block a user