ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

闪照小程序源码拆解:定时器管理、UI组件与广告变现

闪照小程序源码拆解:定时器管理、UI组件与广告变现 简介一款让微信用户实现类QQ“闪照”体验的小程序源码面向微信小程序开发者、运营者以及喜欢尝试新鲜社交玩法的个人用户。基于微信小程序原生组件与模块化目录构建支持用户自主上传照片并像QQ一样自由设定闪照可见时长既可用于好友间的趣味互动也能作为一个轻量工具类小程序接入流量主广告位带来一定收益。压缩包共29个文件总体积仅166KB其中WXML负责页面布局、WXSS负责样式表现、JS与JSON负责交互逻辑和全局配置另附说明文档与合法域名配置指南页面、组件、静态资源等目录划分清晰整体采用原生语法、不依赖重型框架阅读与二次开发门槛较低。已有315人学习浏览尤其适合想通过一个完整案例掌握小程序上传、配置与审核全流程的入门者也可作为功能完整且易定制的社交模板直接改造成自己的作品。1. 微信小程序里的“阅后即焚”闪照源码到底值不值得折腾打开微信对话框你发现对方发来一张图片——点开是模糊的手指长按会提示“闪照不可保存”过几秒图片自动销毁。这是QQ闪照的核心交互逻辑而现在一批小程序开发者正在把这套玩法搬进微信里。这款闪照制作小程序源码做的就是这件事用户上传本地照片自定义闪照的可视时长比如3秒、5秒、10秒接收方看到的是带倒计时的图片时间一到图片从屏幕和缓存里一起消失。它还内置了流量主广告位可以在闪照浏览结束后插入激励视频或Banner把“装逼工具”变成可变现的流量入口。适合三类人想在微信生态里做轻社交玩法的产品经理、刚学完小程序基础想拆一个完整工程的开发者、以及手里有流量想快速上一款工具类小程序试水的运营者。下文不聊概念直接拆源码结构和能跑的细节。2. 源码目录拆解从 colorui 到 app.json 的工程骨架2.1 根目录文件先看清这个工程跑起来需要哪些前置条件解压闪照.zip之后第一眼看到的不是pages而是app.json、app.js、app.wxss以及colorui这个目录。colorui是一套开源的高颜值微信小程序 UI 组件库优势在于不需要 npm 安装直接把colorui文件夹丢进项目根目录在app.wxss里import样式文件即可。这个工程选择 colorui 而不是 WeUI 或 Vant Weapp图的是两件事一是组件视觉更接近社交类产品的圆润风格二是省掉了 npm build 这一步——在微信开发者工具里直接“导入项目”就能看到界面迭代速度明显更快。app.json是整个小程序的全局配置文件路由、窗口样式、tabBar 都在这里声明。打开它看到的关键配置如下{ pages: [ pages/index/index, pages/create/create, pages/preview/preview ], window: { navigationBarBackgroundColor: #1a1a1a, navigationBarTitleText: 闪照, navigationBarTextStyle: white }, sitemapLocation: sitemap.json }pages数组的第一项就是小程序的启动页这里把pages/index/index作为首页意味着用户打开小程序先看到的是闪照列表或功能入口。window里的黑色导航栏配合闪照这种“阅后即焚”的暗色交互视觉上更聚焦照片本身。sitemap.json用于配置微信索引小程序的页面收录规则工具类小程序一般保持默认。2.2 pages、components、common、static 四层职责划分这个源码的四层目录划分逻辑很清晰pages放页面级代码components放可复用组件common放公共工具函数和配置常量static放静态资源图片、图标、占位图。闪照这种功能型小程序核心页面不超过四个功能集中在“创建闪照”和“查看闪照”两条主链路上所以目录层级比电商类小程序扁平得多新手读起来没有负担。common目录里值得单独看的是config.js和utils.js两个文件。config.js维护小程序的基础配置——AppID、接口域名、是否启用流量主广告位、默认闪照时长等。我自己接手这类源码的第一步永远是先打开config.js把配置项过一遍因为大部分“上传后白屏”“广告不显示”的 bug 根源都出在这里。utils.js则封装了格式化时间戳、图片本地路径拼接、节流函数这类通用工具方法。2.3 闪照时间配置的数据流从用户输入到页面读取闪照的核心卖点是“自定义时间”这个值在源码里是通过一条单向数据流来管理的用户在创建页选择时间 → 存入全局storage→ 预览页读取并启动定时器。具体存储结构类似// common/config.js const FLASH_CONFIG { DEFAULT_SECONDS: 5, MAX_SECONDS: 30, STORAGE_KEY: flash_photo_item }; function saveFlashItem(item) { wx.setStorageSync(FLASH_CONFIG.STORAGE_KEY, { ...item, expireAt: Date.now() item.seconds * 1000 }); }saveFlashItem在写入瞬间就算好了expireAt时间戳而不是在读取端临时计算。这样做的好处是即使小程序被微信从后台回收、重新冷启动打开也能通过Date.now()与expireAt的差值判断这张闪照是否已经过期——这个细节决定了“销毁”到底是真的销毁还是只是前端视觉上隐藏。目录/文件职责关键内容app.json全局路由与窗口配置页面注册、导航栏样式、sitemap 引用app.wxss全局样式引入 colorui 样式、重置小程序默认边距pages/页面级逻辑创建、预览、列表、引导页components/可复用组件倒计时圈、图片遮罩、广告占位common/工具函数与常量config.js、utils.js、storage 封装static/静态资源图标、背景图、loading 动画colorui/UI 组件库按钮、卡片、图标等基础样式这张表是我读完全部源码后整理的放在这里的作用是给第一次打开工程的人一个导航改页面样式去pages下对应.wxss改业务配置去common/config.js换图标去static/icons。有一个容易踩的坑是colorui的icon类名是固定枚举值想自定义图标需要去 colorui 的样式文件里找对应uni编码不能直接拿一个本地 PNG 就替换否则会出现“图标位置空白”的问题。3. 闪照核心链路实现拍照、时间选择到定时销毁3.1 照片上传与本地临时路径的取舍闪照本质上是一个“用完即删”的工具照片不应当被持久化到服务器。这个源码采用的是本地临时路径方案用wx.chooseMedia选择或拍摄照片后拿到tempFilePath直接把它写入preview页的image组件。这个路径是微信提供的临时文件路径小程序退出后就失效正好符合闪照“不留痕”的产品预期。// pages/create/create.js async function pickImage() { const res await wx.chooseMedia({ count: 1, mediaType: [image], sourceType: [album, camera], sizeType: [compressed] }); const filePath res.tempFiles[0].tempFilePath; this.setData({ selectedImage: filePath, imageWidth: res.tempFiles[0].width, imageHeight: res.tempFiles[0].height }); }参数sizeType: [compressed]很关键微信会对压缩后的图片做降采样一般不会超过 2048px对闪照这种在手机屏幕上最多看 10 秒的图片压缩反而能减少缩略图渲染卡顿。如果你选择original原图遇到 12MP 以上的照片在低端安卓机上渲染image时会有肉眼可见的延迟闪照体验会被拖垮。sourceType同时允许相册和拍照这个源码默认不锁定拍摄是因为在微信内调用相机需要用户先授权scope.camera而相册选择可以绕过这个授权流程缩短从点击到选完图的时间。3.2 自定义闪照时间的交互实现时间选择用的是wx.showActionSheet这种方式比自定义弹窗省去了大量样式代码而且在 iOS 和 Android 上的原生视觉效果更稳定。源码里把时间档位设为 3/5/10/30 秒四档背后的逻辑是低于 3 秒用户来不及看清高于 30 秒就失去了“闪”的意义。这个档位配置在common/config.js的SECONDS_OPTIONS数组里想调整直接改数组就行。function chooseDuration() { const opts getApp().globalData.SECONDS_OPTIONS.map(item ${item}秒); wx.showActionSheet({ itemList: opts, success: (res) { const seconds getApp().globalData.SECONDS_OPTIONS[res.tapIndex]; this.setData({ duration: seconds }); } }); }这里有个设计细节选完时间后预览页显示的倒计时其实比用户选的值多 1 秒。原因在于用户点击“发送”按钮到接收方打开图片之间存在网络传输延迟如果严格按设定秒数销毁对方打开时可能只剩 2 秒。源码在写入expireAt时额外加了 1000ms 缓冲这个小改动在实际体验中非常关键。3.3 定时器与页面生命周期销毁不是一件简单的事“闪照销毁”听起来只是一个setTimeout后隐藏图片但真实实现必须考虑用户退到后台、切到微信对话框、甚至直接锁屏的场景。这个源码在preview页里用的是onShow里启动定时器、onHide里暂停并记录剩余时间、onUnload里清理定时器并清除图片缓存的三段式管理// pages/preview/preview.js onLoad(options) { this.startCountdown(); }, onHide() { clearInterval(this.timer); this.setData({ remaining: this.currentRemaining }); }, onUnload() { if (this.timer) clearInterval(this.timer); wx.removeStorageSync(FLASH_CONFIG.STORAGE_KEY); }, startCountdown() { const total this.data.flashItem.seconds; this.currentRemaining total; this.timer setInterval(() { this.currentRemaining - 1; this.setData({ remaining: this.currentRemaining }); if (this.currentRemaining 0) { clearInterval(this.timer); this.destroyFlashImage(); } }, 1000); }onHide里暂停而非清除定时器这是一个容易忽略但对体验影响极大的选择。微信小程序的页面在用户点击右上角胶囊按钮返回时并不会立刻触发onUnload而是先走onHide。如果onHide里直接清除了定时器用户从聊天窗口切回来会发现闪照还在等于绕过销毁机制。正确做法是像上面这样暂停计时、记录剩余时间onShow里根据剩余时间恢复倒计时只有onUnload才真正销毁数据和图片。destroyFlashImage内部做的事有两件把预览页image的src置空以及调用wx.removeSavedFile清理本地缓存文件。很多开发者在实现闪照时只做了第一步——图片路径置空但临时文件还残留在微信的本地缓存目录里。对普通用户来说两者没区别但在部分安卓机型上图片路径置空后屏幕会有 0.2 秒的白屏闪烁配合wx.removeSavedFile之后再执行透明度渐变动画可以有效规避这个视觉瑕疵。3.4 合法域名配置闪照也需要服务器通信吗很多人以为纯本地图片处理不需要配置域名但这个源码里实际上包含了一个广告位配置接口用来动态拉取流量主开关和广告位 ID。这就涉及微信小程序的服务器域名白名单机制。在config.txt和合法域名.txt里作者记录了请求接口的域名你需要在微信公众平台后台的“开发管理 → 开发设置 → 服务器域名”里把request合法域名和downloadFile合法域名都填进去。配置项用途不配置的后果request合法域名拉取广告位开关、远程配置接口请求直接失败白屏downloadFile合法域名加载远程图片、广告素材图片加载不出Banner 空白uploadFile合法域名如果有图片上传需求才需要本例不需要可留空需要注意request和downloadFile是两个独立的域名配置项只配了 request 而没配 downloadFile广告素材和远程图片就加载不出来。调试期间可以在微信开发者工具的“详情 → 本地设置”里勾选“不校验合法域名”但提审前必须关闭这个选项否则真机预览会直接报url not in domain list这个报错是刷量最多的拦截点。4. 流量主接入与提审从代码到上线的完整流程4.1 流量主能力的前置条件与代码埋点微信小程序的流量主不是打开就有需要满足两个硬性条件小程序累计独立访客UV不低于 1000且无违规记录。这个源码里已经内置了 Banner 和激励视频Rewarded Video两种广告位的代码骨架但没达到条件前调用wx.createRewardedVideoAd会返回错误码1004这是正常的——你需要先上线跑量等 UV 达标后在“小程序后台 → 流量主 → 广告位管理”里创建广告位拿到adUnitId回填到common/config.js。// common/ad.js function createRewardedAd() { const adUnitId getApp().globalData.REWARD_AD_UNIT_ID; if (!adUnitId) return null; const ad wx.createRewardedVideoAd({ adUnitId }); ad.onError((err) { if (err.errCode 1004) { console.warn(广告组件未初始化完成降级为无广告模式); } }); return ad; }代码里对广告创建失败做了降级处理拿不到adUnitId或广告组件报错时直接返回null闪照功能不受影响。这个设计很关键因为闪照是工具属性广告是增值属性不能用广告的失败阻断用户的闪照体验。1004只是未初始化的提示过几分钟重新拉取即可不应当把它当成严重 bug 上报。4.2 Banner 广告位的摆放策略销毁后再出现闪照预览结束后用户看到的是一个销毁动画加一行文案“闪照已销毁”。Banner 广告位如果放在预览页会破坏倒计时的沉浸感如果放在首页曝光率太低。这个源码的做法是把 Banner 放在“销毁完成”这个状态页上用wx.createBannerAd按需创建销毁动画结束后才插入页面底部。showBannerAd() { const ad wx.createBannerAd({ adUnitId: getApp().globalData.BANNER_AD_UNIT_ID, style: { left: 0, width: 320 } }); ad.onResize((res) { this.setData({ bannerHeight: res.height, bannerWidth: res.width }); }); }wx.createBannerAd的style只接受left、top、width三个值top不写的话默认在屏幕顶部。实际部署时我通常会在销毁页用一个view占住底部位置然后onResize回调里拿到广告真实渲染尺寸后动态撑开容器避免广告被页面自身的overflow: hidden裁掉。Banner 广告的width上限是 320px超过这个值会自动等比缩放但底部留白会变大视觉上不如直接固定 320px 干净。4.3 提审时容易被拒的细节隐私协议与内容安全闪照类小程序天然带“阅后即焚”属性审核团队会重点检查两个点用户协议里是否声明了图片处理规则以及是否有内容安全机制。这个源码的readme.html里给了一份用户协议模板核心条款是“用户上传的图片仅保存在本地设备开发者服务器不存储任何用户照片”。这段话必须出现在小程序的“关于”页面或用户协议弹窗里否则审核有机会以“功能涉及用户隐私且未声明”为由拒审。内容安全方面微信审核不会强制要求本地做图片鉴黄但因为闪照图片是用户生成内容UGC建议在提审前在用户协议里加上“禁止上传违法违规内容”的条款并在小程序里预留一个举报入口。这种做法不一定能保证 100% 过审但能显著降低被要求补充声明的概率。审核期间建议把流量主广告位暂时关闭因为广告内容本身也会被纳入审核范围图片类广告的素材合规性不可控可能拉长审核周期。5. 阅后即焚的边界处理定时器泄漏与截图攻防5.1 定时器泄漏扫码进入预览页的隐藏坑小程序的setInterval不受页面销毁自动清理这是所有使用定时器的功能页都要面对的问题。闪照功能里最隐蔽的场景是用户在预览页倒计时期间通过“识别二维码”跳转到另一个小程序或网页此时preview页进入onHide定时器被暂停如果用户从另一个小程序返回时微信把这个页面从栈里弹出低端机上内存回收onUnload里的clearInterval根本不会执行定时器指针残留在内存里。规避方式是在util.js里维护一个全局的定时器注册表页面创建时向app.globalData.timerRegistry注册页面销毁时统一清理// app.js globalData: { timerRegistry: new Set() }, clearAllTimers() { this.globalData.timerRegistry.forEach(timer { clearInterval(timer); clearTimeout(timer); }); this.globalData.timerRegistry.clear(); }在app.js的onHide生命周期里调用clearAllTimers相当于给所有闪照定时器加了一道保险。这样做有一个副作用用户按 Home 键把小程序退到后台再进来时闪照直接销毁了——但这对闪照功能来说反而是合理行为阅后即焚的语义就是“离开视线即销毁”不需要保留现场。5.2 截图攻防iOS 截屏监听与安卓的限制闪照的一类重要威胁是长按截图。微信小程序里wx.onUserCaptureScreen可以监听到用户的截屏行为这个接口在 iOS 和 Android 上都可用。源码在预览页onLoad时注册了这个监听器截屏触发时弹出一个模态框提示“截图将损害闪照的私密性”。注意这只是提示技术上无法阻止截图——这是微信系统层面的沙箱限制任何小程序都一样。更实用的防截屏手段是减少截图的敏感信息。这个源码在闪照图片上叠加了一层半透明噪点遮罩遮罩透明度在低端安卓机上会随 GPU 渲染能力波动导致部分机型上截图后的图片比实际显示更清晰。如果你追求更强的防截图效果可以考虑把图片渲染到canvas上再做一次二次绘制截图会带走被 canvas 处理后的纹理但代价是渲染性能下降和代码复杂度上升对 MVP 阶段的小工具不值得。5.3 从闪照到更多玩法定时图片分享与群聊场景这个源码的可扩展方向比大多数工具类小程序更有趣。第一个方向是“限时可见的朋友圈卡片”把闪照封装成图片附带一个访问链接对方点击后在半小时内查看过期后提示“内容已被撤回”。第二个方向是群聊场景闪照在群聊里被指定成员打开后立即销毁其他群成员只能看到“对方查看了闪照”的记录。这两个方向都只需要在这个源码的preview页基础上加一层业务状态判断不需要伤筋动骨改架构。验证方法也很简单把时间档位从 3/5/10/30 调整为 60/120/300 秒在开发者工具里用不同网速模拟Low-end mobile和Mid-tier Android观察倒计时是否在锁屏和应用切换后依然准确。实测中setInterval在低端机上会有 0.3~1.5 秒的累计漂移10 秒的闪照实际销毁时间可能在 11 秒左右这在可接受范围内。你要关注的是漂移是否随着时长线性放大如果 300 秒时误差超过 15 秒说明你的页面在后台被微信冻结过此时用Date.now()差值重算剩余时间而不是直接恢复原定时器——这也是为什么第 2 章里坚持把expireAt写入本地存储的原因。本文还有配套的精品资源点击获取
返回列表