uniapp 跨平台开发中的设计哲学与踩坑笔记

82 阅读2分钟

一、为什么选择 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 是解决跨端的好工具,但本质不在于“一套代码”,而是:

  • 样式统一
  • 状态同步
  • 用户体验不割裂

在广告平台的实践中,我摸索出“低侵入 + 高适配”的使用哲学。