Files
lucky_shop/components-diy/diy-group.vue
ZF sun 88921e61d2 fix(splash-screen): 修复H5环境下启动屏关闭后页面空白问题
问题根源分析:
1. diy-group 的 mounted() 在组件挂载时就触发了,但此时 diyData 还没有数据
2.
otifyMounted() 在组件 mount 时立即关闭了 H5 的 uni.showLoading(),但页面内容还没就绪
3. 导致启动屏关闭后,首页内容还是空白的

修复方案:
1. 在 diy-group.vue 中,将 loaded 事件的触发时机改为 diyData watch 中,确保数据加载完成后再通知
2. 在 splash-state.js 中,
otifyMounted() 不再立即关闭 H5 原生 loading,等待页面就绪后由 _doHide() 统一关闭
3. 在 index.js 中,onDiyGroupLoaded() 延迟 500ms 再通知页面就绪,确保内容渲染完成
2026-07-13 10:54:17 +08:00

394 lines
11 KiB
Vue

<template>
<view data-component-name="diy-group" class="diy-group">
<view v-for="(item, index) in diyDataArray" :key="index" :style="item.pageStyle">
<view v-if="addonIsExist.store && item.componentName == 'StoreShow'">
<!-- 门店展示 -->
<diy-store :value="item"></diy-store>
</view>
<template v-if="item.componentName == 'Kefu'">
<!-- 客服按钮 -->
<diy-kefu :value="item"></diy-kefu>
</template>
<template v-if="item.componentName == 'Form'">
<!-- 表单组件 -->
<diy-form :value="item"></diy-form>
</template>
<template v-if="addonIsExist.store && item.componentName == 'StoreLabel'">
<!-- 门店标签 -->
<diy-store-label :value="item"></diy-store-label>
</template>
<template v-if="item.componentName == 'Picture'">
<!-- 单图组组件 -->
<diy-picture :value="item"></diy-picture>
</template>
<template v-if="item.componentName == 'Listmenu'">
<!-- 列表按钮组件 -->
<diy-listmenu :value="item"></diy-listmenu>
</template>
<template v-if="item.componentName == 'Text'">
<!-- 文本 -->
<diy-text :value="item"></diy-text>
</template>
<template v-if="item.componentName == 'Notice'">
<!-- 公告 -->
<diy-notice :value="item"></diy-notice>
</template>
<template v-if="item.componentName == 'GraphicNav'">
<!-- 图文导航 -->
<diy-graphic-nav :value="item"></diy-graphic-nav>
</template>
<template v-if="item.componentName == 'ImageAds'">
<!-- 图片广告 -->
<diy-img-ads :value="item"></diy-img-ads>
</template>
<template v-if="item.componentName == 'Search'">
<!-- 搜索 -->
<diy-search :value="item" :topNavColor="topNavColor" :global="diyGlobalData.global"
:haveTopCategory="haveTopCategory" :followOfficialAccount="followOfficialAccount"></diy-search>
</template>
<template v-if="item.componentName == 'RichText'">
<!-- 富文本 -->
<diy-rich-text :value="item"></diy-rich-text>
</template>
<template v-if="item.componentName == 'HorzLine'">
<!-- 辅助线 -->
<diy-horz-line :value="item"></diy-horz-line>
</template>
<template v-if="item.componentName == 'HorzBlank'">
<!-- 辅助空白 -->
<diy-horz-blank :value="item"></diy-horz-blank>
</template>
<template v-if="item.componentName == 'Coupon' && addonIsExist.coupon">
<!-- 优惠券 -->
<diy-coupon :value="item"></diy-coupon>
</template>
<template v-if="item.componentName == 'GoodsList'">
<!-- 商品列表 -->
<diy-goods-list :value="item"></diy-goods-list>
</template>
<template v-if="item.componentName == 'ManyGoodsList'">
<!-- 多商品组 -->
<diy-many-goods-list :value="item" :global="diyGlobalData.global"
:scrollTop="scrollTop"></diy-many-goods-list>
</template>
<template v-if="item.componentName == 'RubikCube'">
<!-- 魔方、橱窗 -->
<diy-rubik-cube :value="item"></diy-rubik-cube>
</template>
<template v-if="item.componentName == 'Video'">
<!-- 视频 -->
<diy-video :value="item"></diy-video>
</template>
<template v-if="item.componentName == 'Seckill' && addonIsExist.seckill">
<!-- 秒杀 -->
<diy-seckill :value="item"></diy-seckill>
</template>
<template v-if="item.componentName == 'Pintuan' && addonIsExist.pintuan">
<!-- 拼团 -->
<diy-pintuan :value="item"></diy-pintuan>
</template>
<template v-if="item.componentName == 'Groupbuy' && addonIsExist.groupbuy">
<!-- 团购 -->
<diy-groupbuy :value="item"></diy-groupbuy>
</template>
<!-- 拼团返利 -->
<template v-if="item.componentName == 'Pinfan' && addonIsExist.pinfan">
<diy-pinfan :value="item"></diy-pinfan>
</template>
<template v-if="item.componentName == 'Bargain' && addonIsExist.bargain">
<!-- 砍价 -->
<diy-bargain :value="item"></diy-bargain>
</template>
<template v-if="item.componentName == 'Presale' && addonIsExist.bargain">
<!-- 预售 -->
<diy-presale :value="item"></diy-presale>
</template>
<template v-if="item.componentName == 'Notes' && addonIsExist.notes">
<!-- 店铺笔记 -->
<diy-notes :value="item"></diy-notes>
</template>
<template v-if="item.componentName == 'FloatBtn'">
<!-- 浮动按钮 -->
<diy-float-btn :value="item"></diy-float-btn>
</template>
<template v-if="item.componentName == 'LiveInfo'">
<!-- 小程序直播 -->
<!-- #ifdef MP-WEIXIN -->
<diy-live :value="item"></diy-live>
<!-- #endif -->
</template>
<template v-if="item.componentName == 'FenxiaoGoodsList'">
<!-- 分销商品 -->
<diy-fenxiao-goods-list :value="item"></diy-fenxiao-goods-list>
</template>
<template v-if="item.componentName == 'GoodsRecommend'">
<!-- 商品推荐 -->
<diy-goods-recommend :value="item"></diy-goods-recommend>
</template>
<template v-if="item.componentName == 'GoodsBrand'">
<!-- 商品品牌 -->
<diy-goods-brand :value="item"></diy-goods-brand>
</template>
<template v-if="item.componentName == 'Article'">
<!-- 文章 -->
<diy-article :value="item"></diy-article>
</template>
<template v-if="item.componentName == 'MerchList'">
<!-- 商户列表 -->
<diy-merch-list :value="item"></diy-merch-list>
</template>
<template v-if="item.componentName == 'MemberInfo'">
<!-- 自定义会员中心——会员信息 -->
<diy-member-info ref="diyMemberIndex" :value="item" :global="diyGlobalData.global"></diy-member-info>
</template>
<template v-if="item.componentName == 'MemberMyOrder'">
<!-- 自定义会员中心——我的订单 -->
<diy-member-my-order ref="diyMemberMyOrder" :value="item"></diy-member-my-order>
</template>
<template v-if="item.componentName == 'QuickNav'">
<!-- 快捷导航 -->
<diy-quick-nav :value="item"></diy-quick-nav>
</template>
<template v-if="item.componentName == 'PaymentQrcode'">
<!-- 付款码 -->
<diy-payment-qrcode :value="item"></diy-payment-qrcode>
</template>
<template v-if="item.componentName == 'HotArea'">
<!-- 热区 -->
<diy-hot-area :value="item"></diy-hot-area>
</template>
<template v-if="item.componentName == 'FollowOfficialAccount'">
<!-- 关注公众号 -->
<diy-follow-official-account :value="item"></diy-follow-official-account>
</template>
<template v-if="item.componentName == 'Map'">
<!-- 地图组件 -->
<diy-map :value="item"></diy-map>
</template>
<template v-if="item.componentName == 'Audio'">
<!-- 音频 -->
<diy-audio :value="item"></diy-audio>
</template>
<template v-if="item.componentName == 'ImageNav'">
<!-- 图片导航 -->
<diy-image-nav :value="item"></diy-image-nav>
</template>
<template v-if="item.componentName == 'Digit'">
<!-- 数字 -->
<diy-digit :value="item"></diy-digit>
</template>
<template v-if="item.componentName == 'VideoList'">
<!-- 视频列表 -->
<diy-video-list :value="item"></diy-video-list>
</template>
<template v-if="item.componentName == 'BottomNav'">
<!-- 底部导航 -->
<diy-bottom-nav :value="item"></diy-bottom-nav>
</template>
<template v-if="item.componentName == 'CategoryItem'">
<!-- 分类项 -->
<diy-category-item :value="item"></diy-category-item>
</template>
<template v-if="item.componentName == 'Category'">
<!-- 分类 -->
<diy-category :value="item"></diy-category>
</template>
<template v-if="item.componentName == 'Icon'">
<!-- 图标 -->
<diy-icon :value="item"></diy-icon>
</template>
<template v-if="item.componentName == 'Tab'">
<!-- Tab 组件 -->
<diy-tab :value="item" :diyGlobal="diyGlobalData"></diy-tab>
</template>
<template v-if="['ChannelList', 'WechatChannel'].includes(item.componentName)">
<!-- 视频号列表 -->
<diy-channel-list :value="item"></diy-channel-list>
</template>
<!-- 自定义扩展组件 -->
<diy-comp-extend :value="item"></diy-comp-extend>
</view>
</view>
</template>
<script>
// 组件组展示
import DiyMinx from './minx.js'
export default {
name: 'diy-group',
props: {
diyData: {
type: Object
},
scrollTop: {
type: [String, Number],
default: '0'
},
haveTopCategory: {
type: Boolean
},
followOfficialAccount: {
type: Object
},
},
mixins: [DiyMinx],
data() {
return {
diyGlobalData: this.diyData ? this.$util.deepClone(this.diyData) : null,
processedData: null
};
},
watch: {
diyData: {
handler() {
this.diyGlobalData = this.diyData ? this.$util.deepClone(this.diyData) : null;
this.processData();
this._notifyLoaded();
},
deep: true
}
},
created() {
this.processData();
},
mounted() {
if (this.diyData && this.diyData.value) {
this._notifyLoaded();
}
},
computed: {
topNavColor() {
if (!this.diyData?.global) return '';
const { topNavBg, topNavColor } = this.diyData.global;
if (topNavBg) {
return this.scrollTop > 20 ? topNavColor : 'transparent';
}
return topNavColor;
},
diyDataArray() {
if (!this.processedData) {
this.processData();
}
const showModuleData = this.$store.state.diyGroupShowModule
? JSON.parse(this.$store.state.diyGroupShowModule)
: null;
if (!showModuleData || !showModuleData.length) {
return this.processedData || [];
}
if (showModuleData.includes('null')) {
return [];
}
return (this.processedData || []).filter(item =>
showModuleData.includes(item.componentName)
);
}
},
methods: {
_notifyLoaded() {
if (this._loadedTimer) clearTimeout(this._loadedTimer);
this._loadedTimer = setTimeout(() => {
this.$emit('loaded');
}, 300);
},
processData() {
if (!this.diyGlobalData || !this.diyGlobalData.value) {
this.processedData = [];
return;
}
this.processedData = this.diyGlobalData.value.map((item, index) => {
const newItem = this.$util.deepClone(item);
newItem.pageStyle = '';
newItem.moduleIndex = this.diyData.tabIndex !== undefined
? `${this.diyData.tabIndex}-${index + 1}`
: index + 1;
if (newItem.componentName !== 'Search' || newItem.positionWay !== 'fixed') {
newItem.pageStyle = `background-color:${newItem.pageBgColor};`;
if (newItem.margin) {
newItem.pageStyle += `padding-top:${newItem.margin.top * 2}rpx;`;
newItem.pageStyle += `padding-bottom:${newItem.margin.bottom * 2}rpx;`;
newItem.pageStyle += `padding-right:${newItem.margin.both * 2}rpx;`;
newItem.pageStyle += `padding-left:${newItem.margin.both * 2}rpx;`;
}
}
return newItem;
});
}
}
};
</script>
<style lang="scss">
.diy-group {
width: 100%;
}
</style>