一、为什么选择 uniapp?
广告平台的投放端需支持 Web、小程序、APP 三端访问,uniapp 提供了“一套代码,多端输出”的能力。
我主导落地了素材预览页、广告入口页等模块的 uniapp 实现,期间总结出以下核心观点:
- uniapp 的优势:组件一致性、部署灵活性
- 最大的难点:平台差异隐藏 vs 灵活适配的权衡
二、组件抽象哲学:不是复用,而是约定
uniapp 平台组件功能有限,如 button、form、input 样式难统一,于是我们将组件抽象为“可约定样式 + platform 注入”的组合:
<template>
<view :class="[platformClass]">
<slot />
</view>
</template>
<script setup>
import { ref, computed } from 'vue'
const platformClass = computed(() => {
return process.env.UNI_PLATFORM === 'mp-weixin' ? 'btn-mp' : 'btn-h5'
})
</script>
在 style 层做平台差异:
.btn-mp {
padding: 20rpx;
font-size: 28rpx;
}
.btn-h5 {
padding: 12px;
font-size: 14px;
}
三、页面适配策略:宽度单位 & 通用布局系统
- 使用
upx+flex实现横向拉伸适配 - H5 端使用 vw/vh 重置 rem 基准
- 小程序端通过原生样式隔离设置固定字体
// main.scss
html {
font-size: calc(100vw / 375 * 100);
}
四、状态管理经验:统一 Pinia,不再依赖 Vuex
虽然 Vuex 是默认支持方案,但我切换为 pinia,理由是更轻、更组合式、更适配 Composition API。
// stores/ad.ts
export const useAdStore = defineStore('ad', {
state: () => ({ currentAd: null }),
actions: {
setAd(ad) { this.currentAd = ad }
}
})
五、API 调用兼容性踩坑
❌ axios 无法直接在小程序中用
解决方案:使用 uni.request 封装:
export const request = (url, method = 'GET', data = {}) => {
return new Promise((resolve, reject) => {
uni.request({
url: BASE_URL + url,
method,
data,
success: (res) => resolve(res.data),
fail: reject
})
})
}
六、生命周期兼容问题
页面中 onLoad、onShow、onUnload 需要特殊处理,不能与 vue-router 相提并论。
处理方式:组合 hook + platform check
onLoad((query) => {
adId.value = query.id
})
onShow(() => {
fetchAdData()
})
七、发布策略与 CI/CD 配置
- H5:Vite 构建 + CDN 部署
- 小程序:使用 dcloud cli 自动上传至微信公众平台
- App:统一打包后用蒲公英分发
部署脚本片段:
# H5
npm run build:h5
scp dist/build/h5/* user@host:/var/www/ad-preview
# 小程序
npm run build:mp-weixin
dcloud-cli upload --path dist/build/mp-weixin
八、总结:平台统一不是目标,体验一致才是结果
uniapp 是解决跨端的好工具,但本质不在于“一套代码”,而是:
- 样式统一
- 状态同步
- 用户体验不割裂
在广告平台的实践中,我摸索出“低侵入 + 高适配”的使用哲学。