fix: 修复鸿蒙元服务商品详情页空白及接口兼容问题
1. 移除view组件无效的scroll-y属性,避免鸿蒙JSVM静默不渲染导致页面空白 2. 删除冗余的商品分类页面路由配置 3. 为ref调用和接口请求添加try-catch与空值防御,避免极端场景下崩溃 4. 补充鸿蒙元服务接口调用的兼容性处理,确保请求正常发起 5. 调整loading隐藏时机和异常捕获逻辑,优化页面容错能力
This commit is contained in:
@@ -91,22 +91,28 @@ export default {
|
||||
this.modifyGoodsInfo();
|
||||
|
||||
// 初始化商品详情视图数据
|
||||
if (this.$refs.goodsDetailView) this.$refs.goodsDetailView.init({
|
||||
sku_id: this.skuId,
|
||||
goods_id: this.goodsSkuDetail.goods_id,
|
||||
preview: this.preview,
|
||||
source_member: this.source_member,
|
||||
posterParams: this.posterParams,
|
||||
posterApi: this.posterApi,
|
||||
shareUrl: this.shareUrl,
|
||||
goodsRoute: this.goodsRoute,
|
||||
isVirtual: this.goodsSkuDetail.is_virtual,
|
||||
deliveryType: this.goodsSkuDetail.express_type,
|
||||
whetherCollection: this.goodsSkuDetail.is_collect,
|
||||
evaluateConfig: this.goodsSkuDetail.evaluate_config,
|
||||
evaluateList: this.goodsSkuDetail.evaluate_list,
|
||||
evaluateCount: this.goodsSkuDetail.evaluate_count
|
||||
});
|
||||
try {
|
||||
if (this.$refs && this.$refs.goodsDetailView) {
|
||||
this.$refs.goodsDetailView.init({
|
||||
sku_id: this.skuId,
|
||||
goods_id: this.goodsSkuDetail.goods_id,
|
||||
preview: this.preview,
|
||||
source_member: this.source_member,
|
||||
posterParams: this.posterParams,
|
||||
posterApi: this.posterApi,
|
||||
shareUrl: this.shareUrl,
|
||||
goodsRoute: this.goodsRoute,
|
||||
isVirtual: this.goodsSkuDetail.is_virtual,
|
||||
deliveryType: this.goodsSkuDetail.express_type,
|
||||
whetherCollection: this.goodsSkuDetail.is_collect,
|
||||
evaluateConfig: this.goodsSkuDetail.evaluate_config,
|
||||
evaluateList: this.goodsSkuDetail.evaluate_list,
|
||||
evaluateCount: this.goodsSkuDetail.evaluate_count
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('goodsDetailView.init failed:', e);
|
||||
}
|
||||
|
||||
//媒体
|
||||
if (this.goodsSkuDetail.video_url) this.switchMedia = "video";
|
||||
@@ -179,17 +185,19 @@ export default {
|
||||
size: 'big'
|
||||
})
|
||||
};
|
||||
if (this.$refs.goodsPromotion) this.$refs.goodsPromotion.refresh(this.goodsSkuDetail.goods_promotion);
|
||||
try {
|
||||
if (this.$refs && this.$refs.goodsPromotion) {
|
||||
this.$refs.goodsPromotion.refresh(this.goodsSkuDetail.goods_promotion);
|
||||
}
|
||||
} catch (e) { console.error('goodsPromotion refresh failed:', e); }
|
||||
|
||||
if (this.goodsRoute != '/pages_goods/detail') this.setPublicShare();
|
||||
|
||||
// this.getBarrageData();
|
||||
// 性能优化: 商品表单(留言表单)仅在商品详情打开"立即留言"弹窗时才需要,
|
||||
// 不再阻塞首次渲染。改为在后台并发请求, 用户真正打开弹窗时数据已就绪。
|
||||
// 注意: 不再依赖 addonIsExist.form (后端可能未开启 form 插件, 但产品被设为"留言商品"(isinformation=2)
|
||||
// 仍需展示留言表单), 始终尝试加载, getGoodsForm 内部已对失败分支兜底空数组。
|
||||
this._goodsFormPromise = this.getGoodsForm();
|
||||
// 不 await, 释放主流程; 调用方需要时可 await this._goodsFormPromise
|
||||
try {
|
||||
this._goodsFormPromise = this.getGoodsForm();
|
||||
} catch (e) {
|
||||
console.error('getGoodsForm kicked off failed:', e);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('handleGoodsSkuData failed:', e);
|
||||
}
|
||||
|
||||
64
pages.json
64
pages.json
@@ -152,70 +152,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "_components/goods-detail-view/goods-detail-view",
|
||||
"style": {
|
||||
"disableScroll": true,
|
||||
"navigationBarTitleText": "商品分类",
|
||||
"enablePullDownRefresh": true,
|
||||
"componentPlaceholder": {
|
||||
"diy-article": "view",
|
||||
"diy-audio": "view",
|
||||
"diy-bargain": "view",
|
||||
"diy-bottom-nav": "view",
|
||||
"diy-category": "view",
|
||||
"diy-category-item": "view",
|
||||
"diy-channel-list": "view",
|
||||
"diy-channel-video": "view",
|
||||
"diy-comp-extend": "view",
|
||||
"diy-coupon": "view",
|
||||
"diy-digit": "view",
|
||||
"diy-fenxiao-goods-list": "view",
|
||||
"diy-float-btn": "view",
|
||||
"diy-follow-official-account": "view",
|
||||
"diy-form": "view",
|
||||
"diy-goods-brand": "view",
|
||||
"diy-goods-list": "view",
|
||||
"diy-goods-recommend": "view",
|
||||
"diy-graphic-nav": "view",
|
||||
"diy-group": "view",
|
||||
"diy-groupbuy": "view",
|
||||
"diy-horz-blank": "view",
|
||||
"diy-horz-line": "view",
|
||||
"diy-hot-area": "view",
|
||||
"diy-icon": "view",
|
||||
"diy-image-nav": "view",
|
||||
"diy-img-ads": "view",
|
||||
"diy-index-page": "view",
|
||||
"diy-kefu": "view",
|
||||
"diy-listmenu": "view",
|
||||
"diy-live": "view",
|
||||
"diy-many-goods-list": "view",
|
||||
"diy-map": "view",
|
||||
"diy-member-info": "view",
|
||||
"diy-member-my-order": "view",
|
||||
"diy-merch-list": "view",
|
||||
"diy-notes": "view",
|
||||
"diy-notice": "view",
|
||||
"diy-payment-qrcode": "view",
|
||||
"diy-picture": "view",
|
||||
"diy-pinfan": "view",
|
||||
"diy-pintuan": "view",
|
||||
"diy-presale": "view",
|
||||
"diy-quick-nav": "view",
|
||||
"diy-rich-text": "view",
|
||||
"diy-rubik-cube": "view",
|
||||
"diy-search": "view",
|
||||
"diy-seckill": "view",
|
||||
"diy-store": "view",
|
||||
"diy-store-label": "view",
|
||||
"diy-tab": "view",
|
||||
"diy-text": "view",
|
||||
"diy-video": "view",
|
||||
"diy-video-list": "view"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "cart",
|
||||
"style": {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<view>
|
||||
<view scroll-y="true" class="goods-detail" :class="isIphoneX ? 'active' : ''">
|
||||
<!-- 修复鸿蒙元服务: 移除无效的 scroll-y="true" 属性 (scroll-y 是 <scroll-view> 的指令属性)
|
||||
鸿蒙 JSVM 早期版本遇到无效 attribute 会让 view 子树静默不渲染, 导致整个详情页空白 -->
|
||||
<view class="goods-detail" :class="isIphoneX ? 'active' : ''">
|
||||
<view class="goods-container">
|
||||
<!-- AI客服悬浮按钮 -->
|
||||
<view class="ai-chat-float-btn" @tap.stop="$emit('aiChatClick')" v-if="showAIChatBtn">
|
||||
|
||||
@@ -102,11 +102,14 @@ export default {
|
||||
try {
|
||||
await this.getGoodsSkuDetail();
|
||||
} catch (e) {
|
||||
console.error('getGoodsSkuDetail failed on 鸿蒙:', e);
|
||||
console.error('getGoodsSkuDetail failed:', e);
|
||||
// 即使失败也要保证 loading-cover 关闭, 避免空白屏
|
||||
if (this.$refs.loadingCover && typeof this.$refs.loadingCover.hide === 'function') {
|
||||
this.$refs.loadingCover.hide();
|
||||
}
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const ref = this.$refs && this.$refs.loadingCover;
|
||||
if (ref && typeof ref.hide === 'function') ref.hide();
|
||||
} catch (e2) { /* swallow */ }
|
||||
}, 0);
|
||||
}
|
||||
},
|
||||
onHide() {
|
||||
@@ -129,14 +132,28 @@ export default {
|
||||
},
|
||||
// 获取商品详情
|
||||
async getGoodsSkuDetail() {
|
||||
let res = await this.$api.sendRequest({
|
||||
url: '/api/goodssku/detail',
|
||||
async: false,
|
||||
data: {
|
||||
sku_id: this.skuId,
|
||||
goods_id: this.goodsId,
|
||||
let res;
|
||||
try {
|
||||
// 修复鸿蒙元服务: 必须传 async: false !
|
||||
// 当 App.vue 的 boot (lang/theme/remote-config) 未完成时,
|
||||
// sendRequest 在 async !== false 模式下会直接 return undefined (不返回 promise),
|
||||
// 导致 res.code undefined / res.data 抛 TypeError, 整个 onShow 失败.
|
||||
res = await this.$api.sendRequest({
|
||||
url: '/api/goodssku/detail',
|
||||
async: false,
|
||||
data: {
|
||||
sku_id: this.skuId,
|
||||
goods_id: this.goodsId,
|
||||
}
|
||||
});
|
||||
// 防御: 即便 async:false 仍可能在极端情况下返回 undefined
|
||||
if (!res || typeof res !== 'object') {
|
||||
throw new Error('sendRequest returned non-object response (likely boot not complete)');
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getGoodsSkuDetail sendRequest failed:', e);
|
||||
throw e;
|
||||
}
|
||||
let data = res.data;
|
||||
if (data.goods_sku_detail != null) {
|
||||
if (data.goods_sku_detail.promotion_type == 'presale' && data.goods_sku_detail.presale_id) {
|
||||
@@ -176,19 +193,24 @@ export default {
|
||||
goods_id: this.goodsId
|
||||
};
|
||||
|
||||
// 让首屏主区域先绘制: 把非首屏必要的字段变换 (sku_images split, JSON.parse, 属性去重等)
|
||||
// 放到下一个 tick, 微信小程序下首帧明显更快, 用户感知"加载完成"提前约 100-200ms。
|
||||
// 兼容鸿蒙元服务: $nextTick / Promise 在某些 JSVM 实现下不可靠, 用 setTimeout 兜底
|
||||
// 让首屏主区域先绘制
|
||||
// 兼容鸿蒙元服务: $nextTick 在某些 JSVM 实现下不可靠, 用 setTimeout 兜底
|
||||
// #ifdef MP-HARMONY
|
||||
await new Promise(resolve => setTimeout(resolve, 16));
|
||||
// #endif
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-HARMONY
|
||||
await this.$nextTick();
|
||||
// #endif
|
||||
|
||||
// 关闭 loading-cover 提前到 nextTick 后, 让用户看到首屏内容
|
||||
if (this.$refs.loadingCover) this.$refs.loadingCover.hide();
|
||||
// 用 setTimeout 0 推迟到下一个 task, 避开当前 sync 阶段 vendor 报错导致 hide 失败
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const ref = this.$refs && this.$refs.loadingCover;
|
||||
if (ref && typeof ref.hide === 'function') ref.hide();
|
||||
} catch (e) { /* swallow */ }
|
||||
}, 0);
|
||||
|
||||
// 处理商品数据 (同步字段变换 + 后台并发 getGoodsForm)
|
||||
await this.handleGoodsSkuData();
|
||||
|
||||
Reference in New Issue
Block a user