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
198 lines
5.7 KiB
Vue
198 lines
5.7 KiB
Vue
<template>
|
|
<view :style="themeColor">
|
|
<!-- 使用 item.id / componentName 稳定 key 避免 v-for 在 diyData 整体重赋值时把组件整个销毁重建, 引发频闪 -->
|
|
<view v-if="diyData && diyData.value && diyData.value.length">
|
|
<block v-for="(item, index) in diyData.value" :key="item.id || item.componentName || index">
|
|
<view v-if="item.componentName == 'GoodsCategory'">
|
|
<diy-category @tologin="toLogin" ref="category" :value="item"></diy-category>
|
|
</view>
|
|
</block>
|
|
</view>
|
|
|
|
<ns-login ref="login"></ns-login>
|
|
|
|
<loading-cover ref="loadingCover"></loading-cover>
|
|
|
|
<!-- 隐私弹窗 -->
|
|
<privacy-popup ref="privacyPopup"></privacy-popup>
|
|
|
|
<!-- 底部tabBar: loading 期间隐藏, 等 loading-cover 关闭后下一 tick 再挂载, 避免 TabBar 与 loading-cover 同时 GPU 合成导致频闪 -->
|
|
<view id="tab-bar" v-if="!loadingVisible">
|
|
<diy-bottom-nav></diy-bottom-nav>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data() {
|
|
return {
|
|
diyData: { value: [] },
|
|
mpShareData: null, //小程序分享数据
|
|
// 修复底部 TabBar 频闪: 用本地 loadingVisible 状态镜像 <loading-cover> 的可见性,
|
|
// loading-cover 的 spin 动画与 diy-bottom-nav 都是 fixed/z-index 高 + GPU 合成,
|
|
// 在 MP-Weixin 下会互相触发重绘, 让用户看到 TabBar 抖动。
|
|
// 策略: loading-cover 显示期间, 也把 tabBar 先收起来, loading-cover 隐藏后
|
|
// 下一次 nextTick 再放出 tabBar, 把整段 loading 过程的合成层冲突降到最低。
|
|
loadingVisible: true
|
|
};
|
|
},
|
|
onLoad() {
|
|
this.$util.hideHomeButton();
|
|
//刷新多语言
|
|
this.$langConfig.refresh();
|
|
this.getDiyInfo();
|
|
},
|
|
onShow() {
|
|
this.$util.hideHomeButton();
|
|
try {
|
|
// 鸿蒙元服务 JSVM 下 $refs.category 可能为 undefined, 需防御
|
|
// 节流: 避免 onShow 重复触发 pageShow() 中的 getHeightArea(-1) 高耗时选择器查询, 引起频闪和性能损耗
|
|
const now = Date.now();
|
|
if (this._lastPageShowTime && now - this._lastPageShowTime < 500) {
|
|
// 短时间内重复触发, 跳过本次 pageShow
|
|
} else if (this.$refs.category && this.$refs.category[0]) {
|
|
this.$refs.category[0].pageShow();
|
|
this._lastPageShowTime = now;
|
|
}
|
|
} catch (e) {
|
|
console.warn('onShow pageShow failed', e);
|
|
}
|
|
|
|
//小程序分享
|
|
// #ifdef MP-WEIXIN
|
|
this.$util.getMpShare('/pages_goods/category').then(res => {
|
|
this.mpShareData = res;
|
|
}).catch(err => {
|
|
// 如果后台没配置,用默认值
|
|
this.mpShareData = {
|
|
appMessage: {
|
|
title: this.$lang('goods.category.shareTitle'),
|
|
path: '/pages_goods/category'
|
|
},
|
|
timeLine: {
|
|
title: this.$lang('goods.category.shareTitle'),
|
|
query: '/pages_goods/category'
|
|
}
|
|
};
|
|
});
|
|
// #endif
|
|
},
|
|
onUnload() {
|
|
try {
|
|
if (!this.storeToken && this.$refs.login && typeof this.$refs.login.cancelCompleteInfo === 'function') {
|
|
this.$refs.login.cancelCompleteInfo();
|
|
}
|
|
} catch (e) {
|
|
console.warn('onUnload cancelCompleteInfo failed', e);
|
|
}
|
|
},
|
|
methods: {
|
|
getDiyInfo() {
|
|
// 避免重复请求导致布局抖动
|
|
if (this._diyInfoLoading) return;
|
|
this._diyInfoLoading = true;
|
|
|
|
this.$api.sendRequest({
|
|
url: '/api/diyview/info',
|
|
data: {
|
|
name: 'DIY_VIEW_GOODS_CATEGORY'
|
|
},
|
|
success: res => {
|
|
if (res.code == 0 && res.data) {
|
|
const newData = res.data.value ? JSON.parse(res.data.value) : res.data;
|
|
// 仅在数据真正变化时赋值,避免鸿蒙元服务下频繁 re-render 造成频闪
|
|
if (JSON.stringify(newData) !== JSON.stringify(this.diyData)) {
|
|
this.diyData = newData;
|
|
}
|
|
} else {
|
|
this.$util.showToast({
|
|
title: this.$lang('diy.noDiyData')
|
|
});
|
|
}
|
|
},
|
|
fail: err => {
|
|
console.error('getDiyInfo request failed', err);
|
|
this.$util.showToast({
|
|
title: this.$lang('diy.networkError')
|
|
});
|
|
},
|
|
complete: () => {
|
|
this._diyInfoLoading = false;
|
|
if (this.$refs.loadingCover) this.$refs.loadingCover.hide();
|
|
uni.stopPullDownRefresh();
|
|
// loading-cover 收起后, 等下一 tick 让出 frame, 再挂载 diy-bottom-nav
|
|
// (避免两个 fixed 高 z-index GPU 合成层在同帧 mount 触发 MP-Weixin 重绘频闪)
|
|
this.$nextTick(() => {
|
|
this.$nextTick(() => {
|
|
this.loadingVisible = false;
|
|
});
|
|
});
|
|
}
|
|
});
|
|
},
|
|
toLogin() {
|
|
this.redirectTologin('/pages_goods/category');
|
|
}
|
|
},
|
|
onPullDownRefresh() {
|
|
uni.hideTabBar();
|
|
this.getDiyInfo();
|
|
},
|
|
onShareAppMessage() {
|
|
return this.mpShareData?.appMessage || {
|
|
title: this.$lang('goods.category.shareTitle'),
|
|
path: '/pages_goods/category'
|
|
};
|
|
},
|
|
onShareTimeline() {
|
|
return this.mpShareData?.timeLine || {
|
|
title: this.$lang('goods.category.shareTitle'),
|
|
query: '/pages_goods/category'
|
|
};
|
|
},
|
|
onAddToFavorites() {
|
|
return {
|
|
title: this.$lang('goods.category.shareTitle'),
|
|
path: '/pages_goods/category'
|
|
};
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
::v-deep .uni-popup__wrapper.uni-center {
|
|
background: rgba(0, 0, 0, 0.6);
|
|
}
|
|
|
|
::v-deep .uni-popup__wrapper-box {
|
|
border-radius: 0 !important;
|
|
}
|
|
|
|
::v-deep .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
|
|
overflow-y: visible;
|
|
}
|
|
|
|
::v-deep .loading-layer {
|
|
background: #fff !important;
|
|
}
|
|
|
|
// 分类四一级展开
|
|
::v-deep .category-template-4 .template-four .uni-popup__wrapper-box {
|
|
border-radius: 0px 0px 14px 14px !important;
|
|
overflow: hidden;
|
|
}
|
|
|
|
::v-deep .category-template-4 .content-wrap .categoty-goods-wrap .goods-list {
|
|
margin-top: 30rpx;
|
|
}
|
|
|
|
::v-deep .category-template-4 .content-wrap .goods-list .goods-item .footer-wrap .right-wrap .num-action {
|
|
width: 46rpx;
|
|
height: 46rpx;
|
|
}
|
|
|
|
::v-deep .uni-page-refresh-inner .uni-page-refresh__path {
|
|
stroke: rgb(1, 1, 1) !important;
|
|
}
|
|
</style> |