尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

UniApp实战:从零搭建美妆教程微信小程序的跨端开发复盘

发布时间:2026/9/24 21:13:59

资讯中心
01
ARTICLE

UniApp实战:从零搭建美妆教程微信小程序的跨端开发复盘

UniApp实战:从零搭建美妆教程微信小程序的跨端开发复盘
去年底有个做美妆内容的朋友找过来他们团队手上有十来个化妆师和KOL每周稳定产出几十条教程视频和图文干货之前一直在短视频平台和公众号上分发但粉丝的“边看边买”需求一直没接住。我最后用UniApp帮他落地了一套美妆教程微信小程序一套代码编译覆盖微信小程序、H5和后续App端包含教程流、视频播放、图文详情、商品展示、扫码、分享裂变、登录收藏等完整能力。这篇文章不是官方文档搬运是这套平台从选型、开发到上线全过程的一次复盘适合正在做内容社区、教程类小程序或者准备用UniApp接微信小程序的开发者参考。先交代一下项目背景方便后面讲技术选型时大家能对上号。这个平台的核心用户是18到30岁、对美妆护肤有强需求的女性用户她们看教程不只是“看个热闹”而是想知道“这个妆怎么画”“用了哪些产品”“在哪买”。所以从第一版开始产品就不是单纯的内容展示而是内容加电商加社区的组合体。这个定位直接影响了我后续所有技术决策。1. 项目冷启动为什么选UniApp搭美妆教程平台1.1 美妆教程平台的核心需求拆解做项目之前我习惯先列需求清单。美妆教程平台从表面上看起来就是“视频列表加播放页”但真正拆开来看要承接的需求比想象中多得多。内容侧要有教程分类、标签体系、搜索、合集/专题教程形式又分成视频教程、图文教程、产品测评、知识卡片用户侧要有收藏、点赞、评论、分享、关注KOL、浏览历史、学习记录交易侧要有商品展示、购物车、订单、支付后续还要考虑课程付费和会员体系运营侧还要有内容审核、数据统计、弹窗活动、版本公告。这些需求叠加起来它更像一个“内容加社区加电商”的混合体而不是简单的内容展示型应用。这个定位意味着开发过程中会频繁新增页面和改版页面。比如首页信息流样式、教程详情页的信息层级、商品卡片的展示位置都会在上线后根据数据反馈反复调整。如果选了不适合快速迭代的技术方案后面每一次改动都会很痛苦。1.2 对比原生微信小程序、Taro、Flutter再定方案在定技术方案之前我把主流方案都拉出来过了一遍。原生微信小程序性能最好对微信生态的API支持最直接但代码只能跑在微信端以后要出H5、出App全部得重写。Taro适合React技术栈的团队但我们团队前端一直用Vue切过去学习成本不低。Flutter的UI一致性和渲染性能确实强但小程序端支持一直没有那么成熟而且对接微信生态的能力比较受限。UniApp用的是Vue语法一套代码可以同时编译到微信小程序、H5、App生态里现成的组件和插件很多正好匹配我们团队的技术背景和项目快速迭代的需求。提示如果是游戏、实时音视频、人脸识别这类强原生能力场景我更建议用原生小程序或者混合开发UniApp更适合业务逻辑重、原生依赖少的应用。2. 工程基础manifest、pages.json与顶部导航栏适配2.1 项目初始化与微信小程序AppID配置这套平台是用HBuilderX创建的uni-app项目具体流程不复杂打开HBuilderX新建项目选uni-app默认模板填项目名称然后到manifest.json里配置微信小程序相关的参数。AppID一定要在项目一开始就填对。在微信公众平台注册小程序后AppID在“开发管理-开发设置”里能看到它不是随便填的测试号。如果开发阶段用测试号后面发行正式版时忘了改回来会出现各种莫名其妙的编译报错。manifest.json里还需要配置小程序端的基础库版本、权限声明等比如要用到扫码、定位、相册等能力时都要提前在权限列表里声明。开发阶段要把项目跑起来需要在HBuilderX里点击“运行到小程序模拟器”它会生成本地编译产物并自动打开微信开发者工具加载这个产物。首次使用前微信开发者工具的“设置-安全设置”里要打开服务端口否则HBuilderX连不上。本地开发时如果接口是HTTP地址还需要在微信开发者工具的“详情-本地设置”里勾选“不校验合法域名”否则所有请求都会被拦截。2.2 页面结构与tabBar设计美妆教程平台的底部导航我规划了四块首页、分类、商城、我的。首页放教程信息流分类页做妆容类型和品类的细分商城页承载商品和订单入口我的页面放个人资料、收藏、浏览记录和设置。所有页面必须在pages.json里注册而且第一项必须是首页。tabBar需要在pages.json里单独配置图标建议用静态图片或iconfont选中和未选中的颜色要区分开。我用的主题色是偏美妆行业的玫瑰色系选中色是#e05a7a未选中是灰色整体视觉比较贴合女性用户审美。{ pages: [ { path: pages/index/index, style: { navigationBarTitleText: 美妆教程 } }, { path: pages/category/category, style: { navigationBarTitleText: 分类 } }, { path: pages/mall/mall, style: { navigationBarTitleText: 商城 } }, { path: pages/mine/mine, style: { navigationBarTitleText: 我的 } } ], tabBar: { color: #999999, selectedColor: #e05a7a, list: [ { pagePath: pages/index/index, text: 首页 }, { pagePath: pages/category/category, text: 分类 }, { pagePath: pages/mall/mall, text: 商城 }, { pagePath: pages/mine/mine, text: 我的 } ] } }2.3 顶部导航栏高度与自定义导航适配首页顶部要做搜索框、消息入口、每日签到入口微信官方默认导航栏放不下这些自定义元素所以首页用了自定义导航。自定义导航踩过的最大坑就是不同机型的顶部高度完全不一样。iPhone X之后的机型有刘海状态栏高度一般是44px左右普通iPhone是20px安卓机子各家差异更大一般在24px到30px之间。再加上右上角有微信胶囊按钮胶囊的高度和位置在不同机型上也不一样。处理方法是写一个系统信息获取工具每次启动时读取状态栏高度和胶囊按钮位置动态计算自定义导航的总高度和内容区域的paddingTop。const systemInfo uni.getSystemInfoSync() const statusBarHeight systemInfo.statusBarHeight const menuButton uni.getMenuButtonBoundingClientRect() // 导航栏高度 状态栏高度 胶囊高度 上下间距 const navBarHeight menuButton.height (menuButton.top - statusBarHeight) * 2计算出来之后把这个导航栏高度存到globalData里所有用到自定义导航的页面统一获取。核心原则是自定义导航的按钮不能和胶囊重叠内容区域要在胶囊下方留出足够空间。做完这套适配后我实测了iPhone 12、华为Mate 40、小米11、iPad等设备基本都能对齐没有再出现按钮被刘海挡住或间距忽大忽小的问题。3. 教程内容消费视频、图文、富文本与商品展示3.1 教程列表与视频播放方案首页信息流是这个产品的灵魂。每张教程卡片包含封面图、标题、时长、播放量、收藏量、作者头像和昵称。卡片不能做成固定高度不同教程的封面比例和标题长度不一样我用了流式布局让内容自然撑开。视频播放这一块我封装了一个VideoPlayer组件。核心需求是页面里同一时间只能有一个视频在播放如果用户滑到第二个视频第一个必须暂停。实现方案是在play事件里记录当前播放的videoId播放新视频时把上一个视频暂停掉。template view classvideo-box video :idvideo- item.id :srcitem.videoUrl :posteritem.cover playhandlePlay(item.id) endedhandleEnded(item) / /view /template script export default { methods: { handlePlay(id) { if (this.currentId this.currentId ! id) { const ctx uni.createVideoContext(video- this.currentId, this) ctx.pause() } this.currentId id } } } /script这里有几个从实际项目里踩出来的经验。第一iOS端如果页面里创建了多个video实例页面隐藏时不销毁返回时容易没有声音或黑屏我是在onHide和onUnload里把所有视频都stop掉。第二poster封面比例和视频实际比例不一致会出现黑边最好统一封面为16:9。第三video组件自带的控制条在某些安卓机型上会遮挡自绘的按钮如果对UI要求高可以用controls配置关闭默认控件再自己画播放和进度条。3.2 图文教程与mp-html富文本渲染除了视频教程后台内容编辑还会产出大量图文教程。内容团队用的富文本编辑器输出的是HTML字符串。小程序里不能直接渲染HTML字符串我选择了mp-html这个组件。选它的理由很直接支持的HTML标签全table、视频、图片、代码块都能解析支持图片懒加载和点击预览组件体积小插件市场直接下载就能用。// pages.json对应的style中引入组件 usingComponents: { mp-html: /uni_modules/mp-html/components/mp-html/mp-html }mp-html :contentdetailHtml /图文详情里踩过几个坑值得说一下。富文本里的图片地址如果是HTTP小程序里会有合法域名问题需要转成HTTPS图片量大时建议统一上传到对象存储。mp-html默认不开启图片预览需要在组件上设置preview属性。富文本里嵌入视频时视频高度经常撑不开需要额外写样式处理。还有一点是图片懒加载在部分老机型上不稳定如果遇到图片不显示优先检查懒加载配置。3.3 商品展示与交易场景美妆教程平台做到后期内容电商是绕不开的每篇教程详情页下面都要挂“本教程用到的产品”模块。商品卡片有三种状态可购买、已下架、已删除。点击商品卡我选了跳转到自家小程序的商品详情页而不是跳微信小商店或第三方电商H5因为支付转化路径最短用户从教程页到商品页再到支付总共两步就到了。这里要特别提醒一下iOS虚拟支付的问题。卖实体美妆产品走微信支付没问题但如果是虚拟课程、会员、付费教程这类虚拟商品iOS端的虚拟支付会被微信限制支付按钮直接不展示或者调不起支付。我们在课程模块的iOS端做了降级处理引导用户去公众号或App端购买并在详情页明确提示。4. 微信特色能力接入扫码、分享、登录与音频适配4.1 扫码功能与场景跳转这个项目里有一个线下柜台扫码需求用户在化妆品专柜扫柜台上的二维码直接打开对应产品的教程详情页。实现上先用uni.scanCode扫普通二维码再把扫码结果解析成产品ID跳转到详情页。uni.scanCode({ success(res) { const { result } res // result可能是URL或JSON字符串 const productId parseProductIdFromResult(result) uni.navigateTo({ url: /pages/tutorial/detail?id productId }) } })扫码进来后有两个隐藏问题。如果扫码目标是tabBar页面要用uni.switchTab而不是navigateTo否则页面能打开但没有底部导航栏。第二个问题是扫码进入的页面可能没有上一级页面用户点返回时getCurrentPages().length小于2此时直接reLaunch到首页而不是navigateBack否则会白屏。4.2 自定义分享好友和朋友圈美妆内容天生适合做裂变分享。我同时实现了两种分享方式一种是页面右上角菜单转发通过onShareAppMessage实现另一种是页面里放按钮button组件加open-typeshare就能触发分享。分享时一定要带上邀请人参数这样后续才能做推广奖励。path里拼接参数时用uni.getStorageSync获取当前用户ID拼进去。朋友圈分享用的是onShareTimeline它不能带复杂参数一般只拼业务ID。onShareAppMessage() { return { title: this.item.title | 美妆教程, path: /pages/tutorial/detail?id this.item.id inviter (uni.getStorageSync(userId) || ), imageUrl: this.item.cover } }分享功能的细节直接影响转化率。分享卡片标题超过一定长度会被微信截断要控制在20个字以内imageUrl建议用5比4比例视觉上比较饱满分享海报里如果有二维码一定要用小程序码不能放普通二维码识别。这些细节我们都是上线后通过分享点击数据反推优化出来的。4.3 登录与用户信息获取现在微信小程序的登录逻辑已经改成了头像昵称填写能力不再推荐一上来就弹授权框获取用户信息。我这个项目用的是uni.login获取code把code发给后端后端调用code2Session接口换成openid然后生成自定义token返回给前端。头像昵称让用户在个人中心自己填写这样既符合微信审核规范又不会因为弹窗授权被拒导致用户流失。uni.login({ provider: weixin, success(res) { // 把code发给后端后端调code2Session接口获取openid api.login({ code: res.code }).then(({ token }) { uni.setStorageSync(token, token) }) } })这里要提醒两个细节。login返回的code只能用一次而且5分钟有效后端如果处理失败前端要重新调用uni.login获取新code。用户拒绝过授权之后要允许用户从设置页重新打开授权很多项目会漏掉这个兜底一旦用户误拒授权后续所有需要用户信息的接口都会失败。4.4 iOS静音状态下播放音乐的适配美妆教程里大量视频是化妆师边讲解边演示用户经常是随手划到视频就静音看字幕。iOS设备上如果手机侧边静音键打开video组件默认没有声音这是用户感知很强的场景。解决办法是通过给音频组件设置忽略静音键来控制。在uni-app里创建InnerAudioContext时可以设置obeyMuteSwitch为false让音频在静音键打开时仍然出声。但video组件对静音键的控制跟InnerAudioContext不一样。如果业务上非要让视频在静音键下也有声音建议不在video组件里直接控制声音而是额外用透明音频层播放声音视频本身只出画面。这个方案实现成本高一些但对完播率有明显帮助这个需求值得做。5. 从开发到发布HBuilderX发行流程与打包上架5.1 运行与发行微信小程序的完整流程开发阶段在HBuilderX里点击“运行到小程序模拟器”uwp工程会自动编译并打开微信开发者工具。上线阶段走的是“发行-小程序-微信”会生成正式编译产物然后到微信开发者工具中点击“上传”填写版本号和版本描述再去微信公众平台提交审核。发行前后的几个关键检查点不能漏。发行前一定要在manifest.json里确认微信小程序AppID是正式版开发版和正式版AppID混用会出现编译错误。上传前要关闭微信开发者工具里的“不校验合法域名”选项否则本地跑得通线上请求全部失败。微信平台要求所有请求域名必须是HTTPS并且要在小程序后台配置request合法域名、uploadFile合法域名、downloadFile合法域名。这个配置审核很快但要提前做不能等到要发布时才想起。5.2 生命周期合理运用与多域名网络请求配置UniApp的生命周期分三层应用生命周期、页面生命周期、组件生命周期。这个项目的生命周期运用有几个要点。应用onLaunch里做全局登录校验、获取系统信息、初始化数据埋点把结果缓存到globalData。页面onLoad里只做一次初始化onShow里做数据刷新。这个区分特别重要教程列表页从详情页返回时会触发onShow可以在这里刷新收藏状态和播放进度而不需要重新请求整页数据。多域名问题在H5端开发时最明显。接口域名、图片CDN域名、视频CDN域名往往不是同一个如果前端全部写死一个baseURL换环境时改起来非常痛苦。我在项目里维护了一个config.js通过环境变量或编译条件切换。const config { development: { baseUrl: https://dev-api.example.com, cdnUrl: https://dev-cdn.example.com, videoUrl: https://dev-video.example.com }, production: { baseUrl: https://api.example.com, cdnUrl: https://cdn.example.com, videoUrl: https://video.example.com } }实际项目里遇到过H5端跨域问题这种问题前端自己怎么设置都没用需要后端在响应头里配置CORS开发阶段可以让后端开一个临时跨域配置上线前再收紧。5.3 安卓应用市场上架的准备工作美妆教程平台如果要打包成App上架安卓应用市场需要提前准备的东西比想象中多。软件著作权证书是硬性要求一般需要7到15个工作日要提前申请不能等项目做完了才开始办。隐私政策必须有内容包括用户信息收集、使用、存储、共享的说明而且要和App内实际使用的权限一一对应。内容安全审核也是重点如果App里有用户发表的评论内容部分市场要求接入内容审核否则会被驳回。uni-app在HBuilderX里可以云打包生成apk文件流程很快速。但如果要用到uts插件或者自定义原生能力就要走离线打包。离线打包的坑在于原生工程版本和uni-app版本必须严格一致版本对不上就是各种编译失败。能纯前端解决的需求尽量用HBuilderX云打包省时省力。6. 上线后踩坑记录常见问题与排查技巧6.1 视频播放和tabBar切换的视觉问题底部导航闪烁是上线后比较早遇到的问题。最初tabBar里的每个页面在onShow里都会重新请求接口并setData导致页面切换时出现白屏闪烁。解决思路是首次加载后把数据缓存到globalData或storageonShow时先读缓存再静默更新这样切换tab时页面是稳定的。视频列表快速滑动时出现过卡顿原因是列表里所有视频在渲染时都创建了video实例即使还没有播放。优化方案是列表封面统一用懒加载的image组件视频在离开可视区域后不预加载只有真正点击播放时才创建video实例。这样处理后滑动流畅度明显提升。6.2 网络请求与连接报错排查开发过程中遇到一个比较典型的报错handshake failed due to invalid upgrade header: null。这个报错出现在调试WebSocket连接时原因多数是服务端WebSocket握手配置有问题。排查思路分三步先确认服务端确实支持WebSocket且路径正确再检查域名证书是否有效且完整最后确认开发工具里是否打开了“不校验合法域名”的开关。后来把连接地址换成wss并确认证书链完整后就稳定了。更常见的问题是用户手机网络不稳定导致接口请求失败。我在请求封装里统一做了10秒超时和失败提示并对非敏感接口做了一次自动重试。但重试机制要谨慎支付、登录这类幂等性不强的接口不能自动重试否则会造成重复支付或重复下单。6.3 页面返回逻辑和webview返回处理教程详情页里有时需要嵌入活动H5页面用的是webview组件。webview的返回行为和普通页面完全不同webview内部是H5自己的浏览器历史记录不会触发小程序页面的onBackPress。我的处理方式是通过uni.webView.postMessage和H5页面通信H5页面内的返回按钮先调用history.back()如果已经回到H5第一页再发消息告诉小程序端调用navigateBack。微信右上角胶囊的返回按钮会直接退出webview页面需要在小程序onBackPress里做拦截判断。拦截返回提示“教程还没看完确认退出吗”可以通过onBackPress实现但这个生命周期在部分安卓机型上不稳定需要配合pages.json里的navigationStyle配置才能正常工作。这个功能上线后对用户留存有一定帮助但要注意提示弹窗不能太频繁否则用户会反感。6.4 从数据反推内容迭代上线后看后台数据发现教程详情页跳出率偏高大量用户在视频前5秒就退出了。后来内容团队把每期视频的妆前妆后对比片段剪到了开头用10秒高能前情留住用户整体完播率提升了20%多。这个优化虽然是内容侧的动作但产品上的启发很大好的教程平台内容运营和技术架构是强耦合的技术侧要提前把播放数据、停留时长、跳出点位这些埋点做好后面内容团队才能拿到数据做迭代。我维护这套美妆教程小程序大约半年整体感觉是UniApp确实把“一套代码多端复用”这件事做到了尤其团队是Vue技术栈的情况下开发效率提升非常明显但真正的复杂性都在微信生态的边界上。如果你也要做类似项目我的建议是先把内容数据结构和页面栈规划清楚再去研究各种API和组件因为布局和页面流转定了开发只是体力活。另外审核、合规和内容安全这些看起来“不技术”的事情一定要提前做不然功能都做好了才发现上不了架返工成本极高。最后再分享一个技巧如果你做的是内容教程类小程序记得在项目里预留数据埋点方案从第一版就开始统计后面优化内容和推荐策略会非常有用。这个习惯帮我少走了很多弯路也希望对你手上的项目有帮助。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。