Skip to content

跨端开发概览

跨端开发的目标是一套代码在多个平台(微信小程序、H5、App、支付宝小程序等)运行。本章从框架选型到移动端适配基础,覆盖跨端开发全链路。各框架专题见对应文档。

生态地图

                  ┌─────────────────────────────────────┐
                  │          跨端开发框架选型              │
                  └─────────────────────────────────────┘

        ┌───────────────┬───────────┴───────────┬───────────────┐
        ▼               ▼                       ▼               ▼
   ┌─────────┐    ┌─────────┐            ┌─────────┐     ┌─────────┐
   │ uni-app │    │  Taro   │            │   RN    │     │ Flutter │
   │  Vue 栈  │    │ React栈 │            │ 原生映射 │     │ 自绘引擎 │
   └─────────┘    └─────────┘            └─────────┘     └─────────┘
        │               │                     │               │
   ✅ 小程序最佳     ✅ React 小程序      ✅ App 端 RN     ✅ 跨平台一致
   ✅ App 端成熟     ✅ H5 开发体验好     ✅ 热更新灵活     ✅ 高性能自绘
   ✅ HBuilderX      ⚠️ App 端较弱        ⚠️ 小程序不支持   ⚠️ 热更新受限

框架架构对比

维度uni-appTaro 3React NativeFlutter
核心原理编译时:Vue SFC → 小程序模板运行时:模拟 DOM,Reconciler 直出Bridge 调用原生控件Skia 自绘引擎
渲染方式WebView(小程序)/ 原生(App)WebView(小程序)/ 原生(H5)原生控件映射自绘所有像素
默认框架Vue 3 / Vue 2React(也支持 Vue 3)ReactDart
小程序支持⭐⭐⭐ 一流⭐⭐⭐ 一流❌ 不支持❌ 不支持
App 端支持⭐⭐⭐ 成熟(nvue)⭐ 较弱⭐⭐⭐ 原生体验⭐⭐⭐ 高性能
H5 支持
性能(小程序)接近原生(编译优化)略低于原生(setData 桥接)
性能(App)nvue 原生渲染Bridge 瓶颈,新架构改善接近原生
热更新❌(小程序平台审核)❌(小程序平台审核)✅ CodePush(仅 JS)
社区规模最大(DCloud + 插件市场)大(京东 + React 生态)大(Meta + npm 生态)快速增长

选型决策矩阵

按团队栈和业务需求来选:

场景推荐方案理由
Vue 团队 + 需覆盖小程序 + H5 + Appuni-appHBuilderX 一键发布、插件市场最丰富
React 团队 + 只做小程序 + H5Taro 3JSX 天然契合、Web 标准体验、React 零迁移成本
React 团队 + 需 App 端深度原生能力React Native原生控件映射、热更新绕过审核
追求跨平台 UI 像素级一致性Flutter自绘引擎、不依赖平台控件
仅微信小程序且对性能极致要求原生小程序零框架开销、启动最快
选型决策流:

需不需要小程序?
├── 需要 → Vue 还是 React?
│          ├── Vue  → uni-app
│          └── React → Taro 3
└── 不需要 → 主要做 App?
             ├── 是 → React 栈选 RN,否则选 Flutter
             └── 否(纯 H5) → 直接用 Vue/React,不需要跨端框架

共享概念

三个框架各自实现不同,但以下概念是通用的:

条件编译

一套代码多端运行,必须处理平台差异。方式不同但目标一致:

框架条件编译方案示例
uni-app#ifdef / #ifndef 预处理指令// #ifdef MP-WEIXIN
Taroprocess.env.TARO_ENV 环境变量 + Tree Shakingif (process.env.TARO_ENV === 'weapp')
RNPlatform.OS / Platform.select()Platform.select({ ios: ..., android: ... })

原则:能编译时确定就用编译时方案(零运行时开销),运行时才能确定的(如用户设备类型)才用运行时判断。

尺寸适配

所有跨端框架都面临屏幕碎片化问题,各有自适应方案:

框架自适应单位设计稿基准
uni-app / 小程序rpx750rpx = 屏幕宽度
Taropx 自动转 rpxdesignWidth 配置(默认 750)
RN逻辑像素(无单位)Flexbox 布局,通过 Dimensions 获取屏幕尺寸
H5rem / vw / vh详见下方 CSS 单位自适应方案

包体积与分包

小程序主包限制 2MB,所有框架都支持分包加载。uni-app 和 Taro 在 pages.json / app.config.ts 中配置 subPackages,微信小程序底层机制相同。


移动端适配基础

以下内容跨框架通用——不管你用 uni-app、Taro 还是原生 H5,CSS 单位、自适应、1px 边框、安全区域、调试这些知识都用得上。

一、CSS 单位

六种核心单位

单位参照基准缩放?典型场景
px屏幕物理像素边框、阴影等极小值
rpx屏幕宽度 750 等分微信小程序全场景
rem根元素 font-size✅(需 JS)H5 移动端页面
vw/vh视口宽/高度 100 等分✅(纯 CSS)全屏布局、Banner
em父/自身 font-size⚠️ 嵌套叠加组件内局部比例
%包含块对应属性流式布局、弹性网格

关键细节:

  • rpx:小程序专用,750rpx = 屏幕宽度,底层自动换算(iPhone 6 上 1rpx = 0.5px)
  • remhtml { font-size: calc(100vw / 3.75) } → 375 稿下 1rem = 100px,设计稿 16px = 0.16rem
  • em 陷阱:嵌套叠加——父 16px → 子 1.5em = 24px → 孙子 1.5em = 36px(不是 24px)
  • % 陷阱padding-top: 20% 参照父元素宽度,不是高度

使用建议

  • 边框/分割线:px(1px 以下结合 transform)
  • H5 整页适配:优先 vw(纯 CSS),需兼容老安卓选 rem
  • 小程序:直接用 rpx
  • 组件内图标与文字间距:em 保持比例

二、自适应方案

四大方案对比

方案原理优点缺点场景
rem + JSJS 动态设 html 字号兼容好,生态成熟依赖 JS,SSR 不友好传统 H5 活动页
vw/vhCSS 视口单位纯 CSS,SSR 友好无法限最大宽度,vh 受地址栏影响现代移动端 H5
scaletransform: scale() 整体缩放还原度极高坐标需换算,不适合长列表大屏/数据看板
混合vw + rem + 媒体查询灵活,各尺寸体验好设计成本高中大型项目

rem 方案核心代码

js
(function () {
  const setRem = () => {
    const scale = document.documentElement.clientWidth / 375
    document.documentElement.style.fontSize = 100 * Math.min(scale, 1.5) + 'px'
    // Math.min 限制最大宽度,平板不拉伸
  }
  setRem()
  window.addEventListener('resize', setRem)
  window.addEventListener('pageshow', e => e.persisted && setRem())
})()

vw 方案

js
// postcss.config.js
module.exports = {
  plugins: {
    'postcss-px-to-viewport': {
      viewportWidth: 375,
      viewportUnit: 'vw',
      minPixelValue: 1,  // ≤1px 不转换
    }
  }
}

vh 移动端坑

地址栏收起/展开时 100vh 会跟着变,页面跳动。修复:JS 注入 --vh 变量——window.innerHeight * 0.01,CSS 用 calc(var(--vh) * 100) 替代 100vh

面试要点

rem vs vw 怎么选? rem 兼容性好、可设最大宽度限制,但依赖 JS;vw 纯 CSS、SSR 友好,但无法限制最大宽度。中大型项目推荐 vw + rem 混合。

scale 方案致命缺陷? 事件坐标需手动换算(clientX / scale)、SEO 不友好、文本选中异常、不适合长列表。只适合固定一屏的大屏可视化。

三、1px 边框问题

产生原因

Retina 屏 devicePixelRatio ≥ 2,CSS 1px 被渲染为 2~3 个物理像素,视觉偏粗。

DPR=1: 1 CSS px = 1 物理像素  ✓
DPR=2: 1 CSS px = 2 物理像素  稍粗
DPR=3: 1 CSS px = 3 物理像素  明显粗

方案对比

方案兼容性圆角侵入性推荐度
伪元素 + transform✅ 全兼容⭐⭐⭐⭐⭐
box-shadow✅ 全兼容⭐⭐⭐
border-image✅ 较全⚠️⭐⭐⭐
viewport 缩放✅ 全兼容高(整页影响)⭐⭐

伪元素方案(推荐)

css
/* 底部 1px 细线 */
.hairline::after {
  content: '';
  position: absolute;
  bottom: 0; left: 0;
  width: 100%; height: 1px;
  background: #ddd;
  transform: scaleY(0.5);
  transform-origin: 0 0;
}

/* 四边 1px 边框 */
.hairline-border::after {
  content: '';
  position: absolute;
  top: -50%; left: -50%;
  width: 200%; height: 200%;
  border: 1px solid #ddd;
  transform: scale(0.5);
  transform-origin: center;
}

border: 0.5px 直接写半像素——iOS 8+ 支持但安卓大部分机型当 0 不渲染。伪元素 + transform 方案最稳。DPR=3 时 scale(0.5) 其实也够了,肉眼难辨。

四、安全区域适配

iPhone X 起引入刘海屏和底部 Home Indicator。CSS 通过 env(safe-area-inset-*) 获取安全区边距。

html
<!-- ① viewport-fit=cover 让页面撑满全屏 -->
<meta name="viewport" content="width=device-width, viewport-fit=cover">
css
/* ② 顶部导航避开刘海 */
.navbar {
  padding-top: env(safe-area-inset-top);
  /* 兼容 iOS 11.0-11.2 */
  padding-top: constant(safe-area-inset-top);
}

/* ③ 底部 fixed 避开横条 */
.tab-bar {
  padding-bottom: env(safe-area-inset-bottom);
  padding-bottom: constant(safe-area-inset-bottom);
}

constant() 和 env() 的顺序

constant() 写在前面——iOS 11.0-11.2 只认 constant() 它会生效;iOS 11.2+ 两个都认,后面的 env() 覆盖。反过来新版 iOS 会吃到旧值。

非全面屏设备上 safe-area-inset-* 值均为 0,直接加不会影响布局。

五、移动端调试

工具场景能力
vConsole真机快速排查控制台、网络、存储——注入页面,轻量级
Charles/Whistle接口联调、MockHTTPS 抓包、Map Remote、Mock 数据
Safari/Chrome 远程调试深度排查元素审查、断点、性能分析

关键用法:

bash
# Whistle 快速上手
npm install -g whistle
w2 start  # 默认 8899 端口

# 规则示例
https://cdn.example.com/app.js file:///Users/me/local/app.js  # 线上映射本地
api.example.com/user/info resBody://{mock-user.json}             # Mock 接口
  • iOS 调试:手机数据线连 Mac → Mac Safari "开发" → 选择设备和页面 → Web Inspector(需 Mac Safari 版本 ≥ iOS Safari 版本)
  • Android 调试:USB 连接 → chrome://inspect → 点击 inspect → 完整 DevTools

六、移动端常见问题

300ms 点击延迟:现代浏览器在 <meta viewport width=device-width> 时已默认消除(iOS 9.3+、Android Chrome 32+)。FastClick 方案基本成为历史。

iOS 橡皮筋效果body { overscroll-behavior: none; } 一行搞定(iOS 16+ / Chrome 63+),老 iOS 加 -webkit-overflow-scrolling: touch

输入框被键盘遮挡

js
input.addEventListener('focus', () => {
  setTimeout(() => {
    input.scrollIntoView({ behavior: 'smooth', block: 'center' })
  }, 300)  // 等键盘弹出
})

键盘弹出导致 100vh 变小:统一用 JS 注入 --vh,全局用 calc(var(--vh) * 100) 替代裸 100vh

fixed 底部 Android 键盘坑:键盘弹出时 bottom: 0 会跟上来,弹出时隐藏底部栏或切 position: absolute


📖 各框架专题文档

  • uni-app — 生命周期、条件编译、分包、nvue、性能优化
  • Taro — Taro 3 架构、跨端适配、样式方案、性能优化
  • React Native — Bridge 通信、热更新、性能优化、新架构、vs Flutter

基于 VitePress 构建 · 内容持续更新