08-多端适配与条件编译

2 阅读2分钟

🔀 Taro 从零到一(八):多端适配与条件编译

系列导读:Taro 的核心价值在于多端,但各平台总有差异。 本文教你用条件编译和运行时判断优雅处理多端差异。


📊 各平台主要差异

能力微信支付宝抖音H5
TabBar原生原生原生Taro 模拟
分享onShareAppMessageonShareAppMessageonShareAppMessageWeb Share API
支付wx.requestPaymentmy.tradePaytt.pay自定义
登录wx.loginmy.getAuthCodett.login自定义
扫码wx.scanCodemy.scantt.scanCode

🔧 1. 编译时条件编译

文件维度

src/
├── components/
│   └── ShareButton/
│       ├── index.tsx          # 默认实现
│       ├── index.weapp.tsx    # 微信小程序专用
│       ├── index.alipay.tsx   # 支付宝专用
│       └── index.h5.tsx       # H5 专用

Taro 编译时会自动选择对应平台的文件。 例如编译微信小程序时,index.weapp.tsx 优先于 index.tsx

代码块维度

// 环境变量判断
function LoginButton() {
  const handleLogin = async () => {
    if (process.env.TARO_ENV === 'weapp') {
      // 微信登录
      const { code } = await Taro.login()
      await authApi.loginByWechat(code)
    } else if (process.env.TARO_ENV === 'alipay') {
      // 支付宝登录
      const res = await Taro.login()
      await authApi.loginByAlipay(res.authCode)
    } else if (process.env.TARO_ENV === 'h5') {
      // H5 跳转登录页
      Taro.navigateTo({ url: '/pages/login/index' })
    }
  }

  return <Button onClick={handleLogin}>登录</Button>
}

注释条件编译(推荐)

function PaymentButton({ orderId }: { orderId: string }) {
  const handlePay = async () => {
    /* #ifdef weapp */
    // 仅在微信小程序中编译
    const res = await Taro.requestPayment({
      timeStamp: payInfo.timeStamp,
      nonceStr: payInfo.nonceStr,
      package: payInfo.package,
      signType: 'MD5',
      paySign: payInfo.paySign,
    })
    /* #endif */

    /* #ifdef alipay */
    // 仅在支付宝中编译
    await Taro.tradePay({ tradeNO: payInfo.tradeNo })
    /* #endif */

    /* #ifdef h5 */
    // 仅在 H5 中编译
    window.location.href = payInfo.payUrl
    /* #endif */
  }

  return <Button onClick={handlePay}>立即支付</Button>
}

🧩 2. 多端适配工具

// src/utils/platform.ts
import Taro from '@tarojs/taro'

// 当前平台
export const isWeapp = process.env.TARO_ENV === 'weapp'
export const isAlipay = process.env.TARO_ENV === 'alipay'
export const isH5 = process.env.TARO_ENV === 'h5'
export const isTt = process.env.TARO_ENV === 'tt'

// 获取系统信息
export function getSystemInfo() {
  const info = Taro.getSystemInfoSync()
  return {
    platform: info.platform,         // ios / android / devtools
    screenWidth: info.screenWidth,
    screenHeight: info.screenHeight,
    statusBarHeight: info.statusBarHeight || 0,
    safeArea: info.safeArea,
    isIOS: info.platform === 'ios',
    isAndroid: info.platform === 'android',
  }
}

// 安全区域适配
export function getSafeAreaBottom(): number {
  const info = Taro.getSystemInfoSync()
  if (info.safeArea) {
    return info.screenHeight - info.safeArea.bottom
  }
  return 0
}
// 使用
import { isWeapp, isH5 } from '@/utils/platform'

function ShareButton() {
  // 微信小程序使用原生分享
  if (isWeapp) {
    return <Button openType="share">分享给好友</Button>
  }

  // H5 使用自定义分享
  if (isH5) {
    return (
      <Button onClick={() => {
        // 复制链接或调用 Web Share API
        Taro.setClipboardData({ data: window.location.href })
        Taro.showToast({ title: '链接已复制' })
      }}>
        分享链接
      </Button>
    )
  }

  return null
}

📱 3. 样式适配

// 导航栏高度适配
.custom-nav {
  // 微信小程序自定义导航栏需要计算状态栏高度
  padding-top: env(safe-area-inset-top);
}

// 底部安全区域(iPhone X 系列)
.bottom-bar {
  padding-bottom: env(safe-area-inset-bottom);
}

// 多端样式差异
/* #ifdef weapp */
.page { background: #f5f5f5; }
/* #endif */

/* #ifdef h5 */
.page { background: #fff; max-width: 750px; margin: 0 auto; }
/* #endif */

🔌 4. 多端配置

// config/index.ts
const config = {
  // H5 配置
  h5: {
    publicPath: '/',
    devServer: { port: 10086 },
    router: { mode: 'browser' },  // history 模式
  },
  // 微信小程序配置
  mini: {
    postcss: {
      pxtransform: {
        enable: true,
        config: { designWidth: 750 },
      },
    },
    miniCssExtractPluginOption: {
      ignoreOrder: true,
    },
  },
}

✅ 本篇小结 Checklist

  • 理解各平台的主要差异点
  • 掌握文件维度条件编译(.weapp.tsx
  • 掌握注释条件编译(#ifdef
  • 会封装平台判断工具
  • 处理样式适配(安全区域、导航栏)

下一篇预告:《小程序原生能力调用》


本文是「Taro 从零到一」系列第 8 篇,共 10 篇。