ARTICLE DETAIL

资讯详情

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

Uniapp双端壁纸小程序开发:条件编译与瀑布流适配

Uniapp双端壁纸小程序开发:条件编译与瀑布流适配 简介基于Uniapp开发的壁纸小程序源码同时适配微信小程序与抖音小程序面向需要快速上线壁纸类应用的中小开发者、独立创业者和前端学习者。源码涵盖壁纸展示、分类检索、用户交互、图片资源管理等完整功能模块并配有PHP后台接口与基本样式文件可直接作为双端小程序的起步模板或二次开发基础。资源共709个文件包含281个JS逻辑文件、119个Vue页面组件、82个PHP服务端脚本、40个JSON配置及WXML/WXSS/SCSS等样式文件压缩包仅1.72MB结构清晰便于按模块查阅。已有158人学习/下载。借助Uniapp同一套代码编译到双端的特性开发者可同时覆盖微信和抖音两大流量入口省去重复开发成本包内附带使用说明对理解跨端项目组织、接口对接与上线流程也有一定参考价值。1. 壁纸小程序源码双端改造先从Uniapp的适配逻辑入手拿到一套命名为“基于Uniapp开发壁纸小程序源码 微信抖音双端小程序源码.rar”的压缩包时先别急着解压运行。用Uniapp写小程序的人大多有过这种经历微信端一切正常抖音端打开却白屏或者接口能通分享和保存相册直接失效。这并不一定代表源码有缺陷而是Uniapp虽然提供了跨端编译能力两端平台差异却不会自动消失。壁纸类小程序看起来只是图片列表加下载实际上图片加载、相册授权、分享参数都是双端最容易出岔子的地方。这篇内容顺着壁纸小程序的脉络把Uniapp双端开发的工程结构、瀑布流实现和条件编译一层层铺开适合想把已有源码改造成双端、或者正在评估要不要用Uniapp接抖音小程序的开发者。2. Uniapp双端壁纸小程序的工程结构与条件编译核心2.1 为什么壁纸场景选Uniapp比原生双写更划算壁纸小程序的重头戏在图片展示与下载业务逻辑层相对薄这正好适合Uniapp的跨端编译模型。在一套代码里维护列表和详情页微信跟抖音共用同一份Vue模板只需要在两端表现不一致的API处做分支。对比用微信原生WXML和抖音ttml分别实现能省掉大约四成重复UI工作。不过也要看到Uniapp在图片长列表和内存控制上并不比原生有优势后续需要通过懒加载、分页与图片域名CDN把性能兜住。常见做法是直接在HBuilderX里创建uniapp项目把壁纸相关的页面塞进pages目录组件放进components目录。这里有一个容易被忽略的点微信和抖音各自对主包体积有严格限制壁纸图片绝不能放进static目录。凡是静态图、占位图、切图全部走线上地址或CDN否则编译后的包会迅速膨胀抖音工具会直接拒绝上传。2.2 双端编译原理与平台标识Uniapp会将一套JavaScript和Vue模板编译为目标平台的小程序原生文件。在webpack打包阶段dcloudio/uni-app根据预设的transform目标把uni.*调用映射成对应平台底层的wx.*或tt.*。这就是为什么大多数API可以无感使用。但涉及到平台私有参数、权限弹窗或返回结果结构还是得靠条件编译来切分。条件编译的写法是带#ifdef和#endif的注释块配合平台值进行逻辑剔除。常见平台值如下表平台Uniapp条件编译值说明微信小程序MP-WEIXIN微信专用标识抖音小程序MP-TOUTIAO字节跳动小程序标识H5H5浏览器调试用AppAPP-PLUS打包App时的标识示例代码// #ifdef MP-WEIXIN console.log(只在微信小程序输出); // #endif // #ifdef MP-TOUTIAO console.log(只在抖音小程序输出); // #endif这里的关键是条件编译是编译期行为不是运行期判断。未被选中的代码块会被删除不会进入目标平台bundle因此可以放心地在注释块里写平台特有代码。注意#ifdef要单独一行且必须保持大小写。我一般会在utils目录里抽一个platform.js把所有两端差异封装成统一方法页面里只调用这个模块避免在业务页面里散落大量条件编译。2.3 双端目录结构差异与公共目录划分一份Uniapp壁纸源码解压后核心目录通常包括pages、components、static、utils、api等。微信和抖音对子包大小有不同限制壁纸类页面的列表接口尤其要注意分包策略。让pages/index/index作为主包后面接入分类页、详情页、签到页时尽量放到分包里。分包的作用不只是降体积还能把抖音端的首屏启动耗时压下去。如果源码里同时存在mp-weixin和mp-toutiao编译产物不要试图手动改产物目录下的文件所有改动都应该在src下进行然后重新发布。这是拿到所谓双端源码后最容易踩的第一个坑。另一个坑是页面路由配置抖音小程序对pages.json中navigationBarTitleText的处理和微信一致但backgroundColor有细微色差建议在真机上检查不要用模拟器效果定夺。3. 用Uniapp实现壁纸瀑布流接口请求、图片懒加载与分页3.1 瀑布流布局的两种实现方式壁纸小程序最常用的是双列瀑布流。实现方式有两种一种用CSScolumn-count另一种是左右两列分别由两个数组渲染。CSS方案代码简单但拉取新数据追加到页面时会顺序错乱而且图片高度不固定控制不了每一列的数量和位置。我更推荐双数组分列法把服务端返回的图片轮流放进左列和右列这样两列各自独立渲染页面整体滚动。两列高度会有一些偏差但对壁纸类需求来说轻微参差反而更像瀑布流。真正的难点在于图片加载完成后image的height是动态的。如果不处理会出现列表底部下拉刷新后滚动条突然跳一下。解决办法是在onLoad事件里获取图片高度并保存第二次进入页面时直接读取缓存跳过等待过程。这一步可以放到ImageItem组件中做而不是在页面里处理。3.2 核心代码请求、分发与下拉刷新下面给出可参考的分页核心逻辑。假设服务端返回{ code: 0, data: { list: [...] } }每项包含id、title、cover、full字段。template view classgallery view classcol v-for(col, i) in columns :keyi view classcard v-foritem in col :keyitem.id tappreview(item) image :srcitem.cover modewidthFix :lazy-loadtrue classcover loadonLoad(item.id) / text classcard-title{{ item.title }}/text /view /view view v-ifloading classtip加载中.../view view v-else-iffinished classtip没有更多了/view /view /template script export default { data() { return { columns: [[], []], page: 1, loading: false, finished: false }; }, onPullDownRefresh() { this.page 1; this.columns [[], []]; this.finished false; this.fetchList(); }, onReachBottom() { this.loadMore(); }, methods: { fetchList() { this.loading true; uni.request({ url: https://your-api.example.com/wallpaper/list, method: GET, data: { page: this.page, pageSize: 30 }, success: (res) { if (res.data.code 0) { const list res.data.data.list || []; list.forEach((item, idx) { this.columns[idx % 2].push(item); }); this.finished list.length 30; this.page 1; } }, fail: (err) { console.error(请求失败, err); uni.showToast({ title: 加载失败, icon: none }); }, complete: () { this.loading false; uni.stopPullDownRefresh(); } }); }, loadMore() { if (this.loading || this.finished) return; this.fetchList(); }, preview(item) { const urls this.columns.flat().map((x) x.full); uni.previewImage({ urls, current: item.full }); } } }; /script代码逻辑说明onPullDownRefresh重置页码和分列数组onReachBottom触发加载更多idx % 2将数据轮流放入两列flat()拼接所有图片URL供预览lazy-load属性触发小程序内置懒加载。这里没有使用uni-load-more组件因为壁纸列表往往自定义样式用页面触底事件更自由。参数说明page和pageSize是接口标准分页参数壁纸类接口一般还支持category和resolution示例中未加。modewidthFix让图片根据宽度等比缩放高度避免写死高度导致失真。如果想要精确控制每列高度可以在onLoad回调里拿到图片原始尺寸后设置height但那样会牺牲一些灵活性。3.3 接口字段与双端请求差异接口字段建议使用以下约定字段类型说明idstring壁纸唯一IDcoverstring列表缩略图URLfullstring原图URLtitlestring壁纸标题width / heightnumber图片原始尺寸可选双端兼容方面微信与抖音都要求合法域名但抖音的请求头设置和微信有细微差别。如果使用uni.request抖音端不允许直接设置某些头部字段否则会触发errMsg异常。我一般的做法是在success回调里先判断statusCode再区分业务code不要用请求失败回调承载业务错误。另一个常见差别是超时时间抖音小程序的默认超时比微信短最好在uni.request中显式设置timeout: 10000避免真机上出现“接口通但一直转圈”的现象。4. 微信端与抖音端的条件编译保存相册、分享与登录差异4.1 保存图片到相册的完整流程壁纸小程序的高频操作是保存图片。在双端调用uni.saveImageToPhotosAlbum基本可以共用但授权策略不同。微信小程序需要先通过uni.getSetting检查scope.writePhotosAlbum未授权时调用uni.authorize申请抖音部分版本直接调用即可但为了稳妥我会封装一个saveWallpaper方法。function saveWallpaper(filePath) { const canSave () { return new Promise((resolve, reject) { // #ifdef MP-WEIXIN uni.getSetting({ success(res) { if (res.authSetting[scope.writePhotosAlbum]) { resolve(); } else { uni.authorize({ scope: scope.writePhotosAlbum, success: resolve, fail: reject }); } }, fail: reject }); // #endif // #ifdef MP-TOUTIAO uni.authorize({ scope: scope.writePhotosAlbum, success: resolve, fail: reject }); // #endif }); }; canSave().then(() { uni.saveImageToPhotosAlbum({ filePath, success: () uni.showToast({ title: 已保存, icon: success }), fail: () uni.showToast({ title: 保存失败, icon: none }) }); }).catch(() { uni.showToast({ title: 需要相册权限, icon: none }); }); }这里最容易被坑的是抖音端的uni.authorize在部分基础库版本上返回success但权限弹窗并没有出现。遇到这种情况直接降级用tt原生接口条件编译里写tt.saveImageToPhotosAlbum。不要尝试用wx对象在抖音端调用两端的底层对象完全不同。4.2 分享面板与自定义分享好友的参数差异微信和抖音都支持页面内按钮触发onShareAppMessage但标题图片与路径的默认值不同。微信端自定义分享标题需返回{ title, path, imageUrl }抖音端部分版本还支持videoUrl。代码示例onShareAppMessage() { // #ifdef MP-WEIXIN return { title: 这组壁纸太美了, path: /pages/detail/detail?id this.currentId, imageUrl: this.currentCover }; // #endif // #ifdef MP-TOUTIAO return { title: 这组壁纸太美了, desc: 来自壁纸小程序, path: /pages/detail/detail?id this.currentId, imageUrl: this.currentCover, videoUrl: }; // #endif }注意在抖音端如果imageUrl对应的图片没有下载到本地分享卡片可能是空白。抖音对远程图片的加载策略比微信更严格建议把分享封面提前下载到本地临时目录。这个细节在双端源码里经常被遗漏导致抖音用户看到的是纯色卡片。4.3 登录与用户信息授权改造壁纸小程序不一定强制登录但如果要做收藏和上传就要处理uni.login。微信和抖音的返回值都叫code但用于换取openid的地址不同。建议把登录逻辑抽成独立模块在platform.js中通过条件编译导出不同的login函数。获取用户信息时微信在2022年后要求使用头像昵称填写能力抖音则保留独立弹窗。统一的uni.getUserProfile在两端模拟器上表现一致但真机上抖音的userInfo字段可能为空需要做空值兜底。5. 打包前必调的加载页与双端验收姿势5.1 用自定义全屏loading兜住首屏白屏壁纸小程序首屏图片多启动时常出现短暂白屏。微信和抖音的小程序在渲染页面时没有真正的启动图它们展示的是上一个页面或纯白背景。常见做法是给首页增加一个原生loading状态在onLoad中展示uni.showLoading请求返回后隐藏。但这个方法在抖音端偶尔失效因为uni.showLoading在抖音上的动画样式会被忽略只剩下文字。我一般会写一个自定义的全屏loading组件放在首页最顶层并让背景色和列表背景一致从观感上消除白屏。5.2 修改刚进入的加载页面内容在pages.json中给首页页面加上navigationStyle: custom然后在页面模板里用条件编译渲染一个load-view组件。{ pages: [ { path: pages/index/index, style: { navigationStyle: custom } } ] }首页template最外层放自定义loadingv-ifloading控制显隐请求完成后置为false。加载组件的动画建议用CSS而不是JS定时器因为小程序页面被切换到后台时setInterval会被暂停CSS动画则不受影响。如果壁纸数据量大可以考虑在加载组件里放一个canvas绘制的进度条但大多数情况下一个旋转的圆环就够用了。5.3 打包与真机验证的落地步骤在manifest.json的mp-weixin和mp-toutiao配置项里填好各自的appid抖音的appid在小程序后台的应用信息里不是字节跳动的开发者ID。用HBuilderX分别运行到微信开发者工具和抖音开发者工具不要用浏览器调试替代真机验证。真机上重点测三件事保存相册、分享卡片、下拉刷新。模拟器不会触发真实的权限弹窗和相册写入失败必须真机测。最后用发行-小程序分别打包检查unpackage/dist/build/mp-weixin和mp-toutiao产物中是否有残留的wx或tt全局对象调用。如果条件编译写漏产物里会出现跨端调用最典型的就是微信公众号H5里能跑但抖音真机报wx is not defined。如果网络图源加载仍然慢就把图片域名全部切到支持TLS1.2的CDN上并确保域名在抖音后台的安全域名里配置了白名单这往往是抖音端保存相册失败的最后根因。本文还有配套的精品资源点击获取
返回列表