From a6091f6b686aaf24bffb790a026695ae0a2dac48 Mon Sep 17 00:00:00 2001 From: ZF sun <34314687@qq.com> Date: Sat, 18 Jul 2026 16:57:10 +0800 Subject: [PATCH] refactor(commodity-detail): optimize performance and fix UI flicker issues 1. add empty form tip for product message section 2. lazy load goods form to unblock initial page render 3. optimize category and tabbar rendering to fix flicker on WeChat mini-program 4. delay non-critical data processing to improve first-screen rendering speed 5. fix popup blank issue when opening product message form for the first time --- common/js/goods_detail_base.js | 46 ++++-- components-diy/diy-bottom-nav.vue | 57 +++---- components-diy/diy-category.vue | 7 + components/loading-cover/loading-cover.vue | 164 +++++++++++---------- lang/en-us/goods/detail.js | 1 + lang/zh-cn/goods/detail.js | 1 + pages_goods/category.vue | 31 +++- pages_goods/detail.vue | 5 + pages_goods/public/js/detail.js | 63 ++++++-- 9 files changed, 243 insertions(+), 132 deletions(-) diff --git a/common/js/goods_detail_base.js b/common/js/goods_detail_base.js index a29ee79..fafe255 100644 --- a/common/js/goods_detail_base.js +++ b/common/js/goods_detail_base.js @@ -185,9 +185,12 @@ export default { if (this.goodsRoute != '/pages_goods/detail') this.setPublicShare(); // this.getBarrageData(); - if (this.addonIsExist.form) { - await this.getGoodsForm(); - } + // 性能优化: 商品表单(留言表单)仅在商品详情打开"立即留言"弹窗时才需要, + // 不再阻塞首次渲染。改为在后台并发请求, 用户真正打开弹窗时数据已就绪。 + // 注意: 不再依赖 addonIsExist.form (后端可能未开启 form 插件, 但产品被设为"留言商品"(isinformation=2) + // 仍需展示留言表单), 始终尝试加载, getGoodsForm 内部已对失败分支兜底空数组。 + this._goodsFormPromise = this.getGoodsForm(); + // 不 await, 释放主流程; 调用方需要时可 await this._goodsFormPromise }, /** * 刷新商品详情数据 @@ -327,14 +330,35 @@ export default { * 给 detail.vue 的 diy-form 直接消费。所有分支都做兜底初始化,避免下游拿到 undefined。 */ async getGoodsForm() { - const res = await this.$api.sendRequest({ - url: "/form/api/form/goodsform", - data: { - goods_id: this.goodsSkuDetail.goods_id, - format: 'object' - }, - async: false - }); + // 防御: sku 切换/数据未到时 goods_id 可能为 0/空, 此时直接走空数据分支, + // 避免后端拿到非法 goods_id 导致 4xx/5xx 后还把脏数据塞给前端。 + if (!this.goodsSkuDetail || !this.goodsSkuDetail.goods_id) { + const emptyFn = () => { + this.$set(this.goodsSkuDetail, 'goods_form', []); + this.$set(this.goodsSkuDetail, 'goods_form_config', {}); + this.$set(this.goodsSkuDetail, 'goods_form_name', ''); + this.$set(this.goodsSkuDetail, 'goods_form_tip', ''); + this.$set(this.goodsSkuDetail, 'goods_form_banner', ''); + this.$set(this.goodsSkuDetail, 'goods_form_show_banner', false); + this.$set(this.goodsSkuDetail, 'goods_form_show_tip', false); + }; + emptyFn(); + return; + } + let res; + try { + res = await this.$api.sendRequest({ + url: "/form/api/form/goodsform", + data: { + goods_id: this.goodsSkuDetail.goods_id, + format: 'object' + }, + async: false + }); + } catch (e) { + console.warn('getGoodsForm request failed', e); + res = null; + } const empty = () => { this.$set(this.goodsSkuDetail, 'goods_form', []); this.$set(this.goodsSkuDetail, 'goods_form_config', {}); diff --git a/components-diy/diy-bottom-nav.vue b/components-diy/diy-bottom-nav.vue index d6f04ce..638ee0b 100644 --- a/components-diy/diy-bottom-nav.vue +++ b/components-diy/diy-bottom-nav.vue @@ -1,30 +1,35 @@ diff --git a/components-diy/diy-category.vue b/components-diy/diy-category.vue index a7186e6..245efeb 100644 --- a/components-diy/diy-category.vue +++ b/components-diy/diy-category.vue @@ -323,6 +323,13 @@ export default { * 加防御性检查,避免上线后第一次进入崩溃 */ getHeightArea(index) { + // 节流: 500ms 内的重复请求复用上次结果, 避免每次 onShow 都跑 selectAll 触发频闪 + const now = Date.now(); + if (this._lastHeightAreaTime && now - this._lastHeightAreaTime < 500 && this.heightArea && this.heightArea.length) { + if (index != -1 && index < this.categoryTree.length - 1 && Array.isArray(this.$refs.categoryItem) && this.$refs.categoryItem[index + 1]) this.$refs.categoryItem[index + 1].getGoodsList(); + return; + } + this._lastHeightAreaTime = now; let heightArea = []; if (!query || typeof query.selectAll !== 'function') { query = uni.createSelectorQuery && uni.createSelectorQuery().in(this); diff --git a/components/loading-cover/loading-cover.vue b/components/loading-cover/loading-cover.vue index e1072b6..9804158 100644 --- a/components/loading-cover/loading-cover.vue +++ b/components/loading-cover/loading-cover.vue @@ -42,82 +42,90 @@ export default { }; - diff --git a/lang/en-us/goods/detail.js b/lang/en-us/goods/detail.js index d9967fe..8b30d7e 100644 --- a/lang/en-us/goods/detail.js +++ b/lang/en-us/goods/detail.js @@ -115,6 +115,7 @@ export const lang = { // Product Message productMessage: 'Product Message', + formEmptyTip: 'No message fields to fill', // AI Customer Service aiCustomerService: 'AI Assistant', diff --git a/lang/zh-cn/goods/detail.js b/lang/zh-cn/goods/detail.js index 606d3c4..2b9b0ff 100644 --- a/lang/zh-cn/goods/detail.js +++ b/lang/zh-cn/goods/detail.js @@ -108,6 +108,7 @@ export const lang = { // 商品留言 productMessage: '商品留言', + formEmptyTip: '暂无需填写的留言字段', // 智能客服 aiCustomerService: '智能客服', diff --git a/pages_goods/category.vue b/pages_goods/category.vue index dd813d7..1985b43 100644 --- a/pages_goods/category.vue +++ b/pages_goods/category.vue @@ -1,7 +1,8 @@