UniApp 跨端实战:一个代码库跑通微信小程序 + H5 + App 的直播电商
久滴直播电商平台 · 技术博客系列 第 11 篇
🔖 标签:
UniApp跨端开发小程序H5
前言
直播电商产品的用户端需要覆盖多个平台——iOS App、Android App、微信小程序、H5 网页。如果每个平台都独立开发,人力成本和维护成本都会翻倍。
久滴直播电商平台选择 UniApp 作为跨端方案,一套代码同时编译到微信小程序、H5 和 App 三端。本文将分享这套方案在直播电商场景下的分包架构、nvue 原生渲染、组件化设计和多环境配置等实践经验。
目录
- 为什么选 UniApp?
- 分包架构设计
- nvue 原生渲染:直播详情页的性能优势
- 组件化设计:pkg-live 的 20+ 组件
- Hooks 封装:直播状态管理
- 多环境配置与 API 对接
1. 为什么选 UniApp?
常见的跨端方案对比:
| 方案 | 优点 | 缺点 |
|---|---|---|
| Flutter | 性能好,UI 一致 | 不支持小程序,生态偏原生 |
| React Native | 社区大,性能好 | 不支持小程序,学习成本高 |
| UniApp | 全平台覆盖,Vue 生态 | 性能略逊原生,部分 API 限制 |
| Taro | React 生态,支持多端 | 社区不如 UniApp 活跃 |
对于直播电商场景,UniApp 的优势在于:
- 全平台:一套代码编译到微信小程序、H5、iOS、Android
- Vue 生态:团队已有 Vue 经验,上手成本低
- nvue 原生渲染:对性能要求高的页面(如直播详情页)使用原生渲染
- 条件编译:
#ifdef/#ifndef处理平台差异
2. 分包架构设计
微信小程序对主包大小有 2MB 限制,超过限制需要用分包。久滴 UniApp 端采用业务分包设计:
{
"pages": [
{ "path": "pages/index/index" }
],
"subPackages": [
{
"root": "pages/pkg-mall",
"pages": [
{ "path": "mall-classify/index" },
{ "path": "goods-detail/index" },
{ "path": "submit-order" },
{ "path": "shopping-cart" }
]
},
{
"root": "pages/pkg-order",
"pages": [
{ "path": "order-list" },
{ "path": "order-detail" },
{ "path": "aftersale-apply" }
]
},
{
"root": "pages/pkg-live",
"pages": [
{ "path": "live-list" },
{ "path": "live-detail" },
{ "path": "live-playback" }
]
},
{
"root": "pages/pkg-info",
"pages": [
{ "path": "info-detail" },
{ "path": "video-detail" },
{ "path": "info-list" }
]
},
{
"root": "pages/pkg-coupon",
"pages": [
{ "path": "coupon-list" },
{ "path": "coupon-center" }
]
}
]
}
分包策略:
- 主包:只放首页和公共组件,保持尽量小
- pkg-mall:商城相关(商品分类、详情、购物车、下单)
- pkg-order:订单相关(列表、详情、售后)
- pkg-live:直播相关(列表、详情、回放)
- pkg-info:资讯内容
- pkg-coupon:优惠券
每个分包独立加载,用户进入对应功能时才下载相关代码,首屏加载速度大幅提升。
3. nvue 原生渲染:直播详情页的性能优势
UniApp 默认使用 WebView 渲染页面。对于直播详情页这种需要同时播放视频流、渲染弹幕、展示商品列表的高性能场景,WebView 的性能可能不够理想。
久滴平台将直播详情页使用 .nvue(native vue)格式,启用原生渲染:
pages/pkg-live/
├── live-list.vue # 直播列表(WebView 即可)
├── live-detail.nvue # 直播详情(nvue 原生渲染)★
├── live-playback.vue # 直播回放
└── components/
├── live-chat.vue # 弹幕聊天组件
├── popup-prods.vue # 商品列表弹窗
├── live-detail-item.vue # 直播间卡片
└── ...
nvue 的优势:
- 视频播放更流畅:原生
<video>组件直接使用系统播放器 - 弹幕渲染不卡顿:原生 List 组件复用视图,不会因消息量大而卡顿
- 滑动切换更顺滑:原生 List 的上下滑动切换直播间体验接近原生 App
同时,通过条件编译处理 H5 端的差异:
<!-- App/小程序端:使用原生 video -->
<!-- #ifndef H5 -->
<video
:src="src"
:controls="false"
:show-fullscreen-btn="false"
object-fit="cover"
/>
<!-- #endif -->
<!-- H5 端:使用 TCPlayer Web SDK -->
<!-- #ifdef H5 -->
<view :id="containerId" class="tcplayer-container" />
<!-- #endif -->
4. 组件化设计:pkg-live 的 20+ 组件
直播分包包含 20+ 个组件,按功能分组:
components/
├── adapter-list.vue # 直播间列表适配器
├── adapter-swiper.vue # 直播间轮播适配器
├── live-chat.vue # 弹幕聊天组件(核心)
├── live-detail-item.vue # 直播间商品卡片
├── live-options.vue # 直播间操作栏
├── popup-prods.vue # 商品列表弹窗
├── popup-comment-input.vue # 评论输入弹窗
├── popup-audience.vue # 观众列表弹窗
├── popup-more-live.vue # 更多直播弹窗
├── msg-product.vue # 商品消息卡片
├── host-audience.vue # 主播/观众切换
├── introducing-ani.vue # 商品讲解动画
└── more-live.vue # 更多直播入口
每个组件都有独立的 .scss 样式文件,实现了样式隔离和可复用性。
弹幕组件的消息处理
live-chat.vue 是直播间最核心的交互组件,处理弹幕消息的接收、去重、渲染和滚动控制:
const onGetMsgList = async (list: any[]) => {
// 过滤当前群的消息
const filteredMsgList = list.filter((item) => item.to === curGroupId.value)
for (const item of filteredMsgList) {
const targetItem = msgList.value.find((msg) => msg.ID === item.ID)
// 去重 + 非空判断
if (!targetItem && item.payload?.text) {
const isAtBottom = await isScrollAtBottom()
msgList.value.push({
ID: item.ID,
userName: item.nick || '未知用户',
msg: item.payload.text,
})
// 只有用户处于底部时才自动滚动
if (item.isSelfMsg || isAtBottom) {
setScrollToBottom()
}
}
}
}
5. Hooks 封装:直播状态管理
useLiveRoom.ts 封装了直播间的状态管理逻辑:
// hooks/useLiveRoom.ts
export function useLiveRoom() {
const chat = ref<any>(null)
const currentLiveIndex = ref(0)
const liveList = ref<ILiveItem[]>([])
// 进入直播间群
const enterLiveRoom = async (index: number, oldIndex: number) => {
const oldLiveItem = liveList.value[oldIndex]
const liveItem = liveList.value[index]
// 退出旧群
if (oldLiveItem?.streamName) {
await imHook.exitLiveRoom(oldLiveItem.streamName)
}
// 加入新群
if (liveItem?.streamName) {
await imHook.enterLiveRoom(liveItem.streamName)
}
}
// 滑动切换直播间
const handleListScroll = (event: any) => {
uni.$emit(GlobalEventEnum.LIVE_SWIPING)
if (!event.isDragging) {
const i = Math.round(Math.abs(event.contentOffset.y) / windowHeight)
if (i !== currentLiveIndex.value) {
const old = currentLiveIndex.value
currentLiveIndex.value = i
enterLiveRoom(i, old)
}
}
}
return { chat, currentLiveIndex, liveList, handleListScroll }
}
直播间切换时的播放器懒加载也很关键:
const onTimeUpdate = () => {
if (!props.isCurrent) pause() // 非当前页自动暂停播放
}
6. 多环境配置与 API 对接
UniApp 通过 .env 文件管理不同环境的配置:
# .env.development
VITE_API_BASE_URL=http://localhost:48080
# .env.production
VITE_API_BASE_URL=https://api.kudi.net.cn
API 调用封装在统一的请求模块中:
// utils/request.ts
const http = uni.$uv.http
http.interceptors.request.use((config) => {
const token = uni.getStorageSync('token')
if (token) {
config.header.Authorization = `Bearer ${token}`
}
return config
})
http.interceptors.response.use((response) => {
const { code, data, msg } = response.data
if (code === 0) return data
uni.showToast({ title: msg, icon: 'none' })
return Promise.reject(new Error(msg))
})
总结
本文分享了久滴直播电商平台 UniApp 跨端开发的实践经验:
- 业务分包:pkg-mall / pkg-order / pkg-live / pkg-coupon 按功能域分包,满足小程序 2MB 主包限制
- nvue 原生渲染:直播详情页使用 nvue,视频播放和弹幕渲染性能接近原生
- 条件编译:
#ifdef H5/#ifndef H5处理平台差异(如 TCPlayer vs 原生 video) - 组件化设计:20+ 组件按功能分组,弹幕组件实现去重、自动滚动、智能渲染
- Hooks 封装:useLiveRoom 封装直播间切换、群管理、播放器懒加载等逻辑
下一篇是本系列的收官之作,我们将深入会员激励体系的设计。
📦 久滴直播电商平台 是一个基于 Spring Boot 3 + Vue3 + UniApp 的全栈开源直播电商解决方案。
🔗 GitHub:
https://github.com/jiudi-dev/live-mall-community(Community 版)如果觉得本文对你有帮助,欢迎 Star ⭐ 支持!
更多推荐



所有评论(0)