
选型永远不只是技术问题。当领导抛出“做一个微信小程序顺便以后还要覆盖支付宝、百度、抖音甚至以后可能还要 App 端”这种需求时摆在桌面上的选项看起来很多但你真正纠结的其实是两句话用原生写稳但慢用跨平台写快但要接受某些不可控。这样一个朴素的问题背后却牵扯工程化程度、团队技术栈、长期维护成本、多端一致性、第三方 SDK 适配这些现实阻力。本文尝试把原生小程序开发、uni-app、Taro 三者放在同一张表里做对比不预设立场从语法、运行机制、工程化、性能、生态、团队成本、踩坑边界等方面完整拆开来看。如果你手头正有一个小程序项目要启动或者你在负责团队的技术选型这篇文章的建议部分可以直接拿来做评审参考。全文不依赖任何商业机构的官方宣传口径尽量用工程上的实际约束来说话。1. 背景与核心概念1.1 小程序开发为什么会出现“框架之争”从 2017 年微信小程序上线开始小程序这种“无需安装、即用即走”的应用形态逐渐成为移动端业务的一个重要入口。随后支付宝小程序、百度智能小程序、字节跳动小程序、QQ 小程序陆续出现各家平台在底层能力和开放接口上各有侧重但又都遵循相似的页面-组件-API 逻辑。问题也出在这里。如果只做微信小程序原生开发完全足够。但一旦业务需要覆盖多端每个端都从零开始写一套逻辑维护成本会成倍上涨。比如一个电商项目微信小程序一套代码支付宝小程序又要重新处理登录、支付、路由抖音小程序可能还要改组件写法。这种重复劳动催生了跨平台框架的需求写一套代码通过编译和运行时适配同时输出到多个小程序平台甚至还可以输出到 H5 和 App。这就是 uni-app 和 Taro 存在的最根本原因。它们不是要取代原生开发而是在“多端交付”这个约束下提供更高效的生产力方案。1.2 几种技术路线的准确区别先明确三个概念后面所有对比都基于这个框架。原生小程序开发原生小程序开发指直接使用微信官方提供的 WXML、WXSS、JS/TS 以及微信开发者工具进行开发。需要注意这里说的“原生”是相对于跨平台框架而言不代表没有工程化工具。现在做原生小程序同样可以用 npm、TypeScript、ESLint、自动化测试等现代前端工程化手段。原生方式的优势是不依赖任何中间编译层微信新增能力官方会第一时间支持调试链路最短出现问题时定位最快。uni-appuni-app 是由 DCloud 团队推出的跨端框架基于 Vue 语法使用 Vue 2 或 Vue 3 编写代码通过 HBuilderX 或 CLI 方式创建项目。编译器会把 Vue 单文件组件.vue编译成各个小程序平台能够识别的代码。uni-app 的覆盖面很广支持微信、支付宝、百度、字节、QQ、快手小程序还能编译到 H5 和 AppApp 端通过 WebView 或 uni-app x 这样的新方案实现。TaroTaro 是由京东凹凸实验室现京东前端团队开源的跨端框架以 React 语法为基底支持 React 语法写小程序。Taro 3 之后的架构发生了变化不再像 Taro 1/2 那样把 React 代码编译成小程序原生语法而是将整个 React 运行时直接在小程序上运行这样能够保证 React 生态中大量成熟库在 Taro 项目中继续可用。Taro 支持微信、支付宝、百度、字节、QQ 小程序及 H5 端也能通过 Taro Native 的方式去做 React Native 端的扩展。1.3 一个容易混淆的话题小程序跨平台框架算不算“编译型”方案经常能看到关于 Taro/uni-app 是编译时还是运行时的讨论。Taro 3 之后采用的是“运行时 编译时”结合的方式把 React DOM 树映射到小程序的自定义组件树而不是把 React 代码逐行翻译成 WXML。uni-app 则更偏向编译时方案会在编译阶段解析 .vue 文件、拆分模板与逻辑把模板转成目标平台支持的模板语法。理解这个差异对后面排查性能问题很有帮助凡是带运行时的方案框架代码本身会有基础包体积凡是带编译的方案某些动态渲染、复杂表达式、高阶组件用法可能都会因为编译限制而被卡住。2. 环境准备与版本说明做技术对比不能停留在口头上最好把本地开发环境搭起来实际创建项目试试。下面给出三套环境的搭建方式重点是演示配置思路不同时间节点下你安装到的工具版本很可能不同所以这里不锁死版本号。2.1 原生小程序开发环境原生小程序开发至少需要微信开发者工具稳定版即可建议开启“服务端口”Node.js用于 npm 包管理建议 LTS 版本微信小程序后台申请一个测试 AppID没有正式 AppID 时可以用测试号但部分能力受限创建项目时在微信开发者工具中选择“小程序”填入 AppID模板可先选择 JavaScript 基础模板后面按需加入 TypeScript。2.2 uni-app 开发环境HBuilderXDCloud 官方 IDE或纯 CLI 方式Node.js 环境微信开发者工具使用 HBuilderX 创建项目的路径是文件 - 新建 - 项目 - 选择 uni-app 模板。如果习惯 CLI也可以执行npx degit dcloudio/uni-preset-vue#vite my-uni-app cd my-uni-app npm install npm run dev:mp-weixin说明dev:mp-weixin是编译到微信小程序端的开发模式命令执行后会在dist/dev/mp-weixin目录生成编译产物然后通过微信开发者工具导入这个目录。2.3 Taro 开发环境Node.js建议 16 以上pnpm 或 npm微信开发者工具创建项目的标准命令npx tarojs/cli init my-taro-appCLI 会交互式询问框架类型React/Vue、模板类型、TS 支持等选择 React TypeScript 微信小程序模板即可。cd my-taro-app npm install npm run dev:weapp编译完成后产物位于dist目录同样通过微信开发者工具导入。这里给你一个发自实战的建议不要只看“创建项目成功”就下结论。选型前一定三家各跑一个 Hello World分别体验一下改一行代码后的编译耗时、首次预览包体大小、真机调试的顺畅度。这三项体验差异往往比官方文档的性能对比数据更真实。3. 核心技术机制拆解3.1 原生小程序的双线程模型理解小程序原生开发必须先理解微信小程序的运行环境。小程序不是跑在普通浏览器里而是基于微信客户端提供的 JSCoreiOS和 V8Android环境运行逻辑层同时用 WebView 渲染视图层。逻辑层和视图层之间不能直接通信只能通过微信客户端原生注入的setData通道传递数据。setData每次调用本质上是一次从逻辑层到视图层的异步消息传递。这个机制带来的最直观影响是不要在setData里塞大对象和频繁变化的数据。不要把整个 list 数据全量 setData只传变更项。不要在滚动等高频事件回调里直接 setData。原生开发的所有性能优化技巧几乎都围绕“如何减少 setData 频率和数据量”展开。这是原生小程序的底层约束跨平台框架同样无法绕开因为最终它们还是要调用小程序原生setData来更新界面。3.2 uni-app 的编译映射逻辑uni-app 选择了 Vue 语法作为开发语言一个典型的页面是这样的!-- pages/index/index.vue -- template view classcontainer text classtitle{{ title }}/text button typeprimary clickhandleClick点击/button /view /template script setup import { ref } from vue const title ref(Hello uni-app) function handleClick() { title.value 你点击了按钮 } /script style .container { padding: 30rpx; } .title { font-size: 32rpx; } /style这段代码如何变成一个微信小程序页面简要流程如下template被编译为 WXML。style中的 rpx 单位被保留部分不支持的 CSS 选择器会被处理或移除。script setup被编译为小程序页面的 JS 逻辑。view、text、button这些标签会被映射为微信原生组件view、text、button。所以uni-app并不是一个运行时容器把 Vue 应用装进去而是像一个“源到源编译器”把 Vue SFC 转换为小程序可运行的代码。正因为如此它的限制也来自编译层如果你在代码里用了浏览器独有能力例如直接操作window、document编译时能放过你但运行时在微信小程序里必然报错。3.3 Taro 3 的运行时方案Taro 3 的架构与 uni-app 的思路不同。Taro 3 把 React 的 reconciler 层接入到小程序的自定义组件树中简单说就是在小程序运行时环境中模拟了一个 React DOM 树让 React 组件逻辑可以直接跑起来再做一层映射渲染到小程序原生组件。下面是一个 Taro 页面示例// src/pages/index/index.tsx import { View, Text, Button } from tarojs/components import { useState } from react export default function Index() { const [title, setTitle] useState(Hello Taro) return ( View classNamecontainer Text{title}/Text Button onClick{() setTitle(你点击了按钮)}点击/Button /View ) }从开发者视角看代码中的View、Text、Button都是 React 组件但它们在运行时并不生成真实的浏览器 DOM而是经过 Taro 的 React reconciler 映射成小程序原生组件。这个设计让 Taro 项目能直接复用 React 生态里大量不依赖浏览器 DOM 的库也让 React 开发者上手成本降到很低。但运行时有代价将 React 运行时塞进小程序逻辑层后初始化时间会比原生方式更长包体积也会增加。这也是 Taro 社区一直关心的性能问题。3.4 动态渲染能力的边界原生小程序有wx:if、wx:foruni-app 有v-if、v-forTaro 有 JSX 表达式。表面上看都能做列表渲染和条件渲染但在复杂场景下的动态更新能力不一样。原生和 uni-app 这类模板编译方案模板里的结构基本静态化条件分支、循环都会被预先分析优化空间大但写动态组件、根据运行时数据决定渲染哪个组件时会比较吃力。Taro 因为运行时有 React 的参与理论上可以用 React 的 render props、高阶组件、context 等模式组织代码在复杂组件逻辑上表达力更强。需要明确表达力不等于性能。React 在小程序上动态 diff 一棵组件树开销天然比模板编译出来的命令式渲染大。实际项目中如果页面结构简单、以静态展示为主模板方案更稳如果逻辑复杂、状态联动多、组件复用度高Taro 的 React 心智模型会让人写起来更顺手。4. 原生、uni-app、Taro 横向能力对比进入实操前先给出横向对比总表。这张表基于常见环境下的通用特性具体数据要以你当前测试环境为准。维度原生小程序开发uni-appTaro开发语言JS/TS WXML WXSSVue 2 / Vue 3 语法React / Vue 3 语法上手门槛需要理解小程序特有概念会 Vue 基本能上手会 React / Vue 基本能上手微信新能力跟进官方同步最快依赖 DCloud 编译支持依赖社区升级适配多端覆盖仅微信端微信/支付宝/百度/字节/H5/App微信/支付宝/百度/字节/H5/RN性能表现最优较优接近原生模板方案中上运行时方案有额外开销包体积最小基础库会增加部分体积React 运行时体积开销较大动态化能力模板语法限制模板语法限制React 表达式能力强调试体验微信开发者工具全链路需在微信工具中调试编译产物需在微信工具中调试编译产物生态资源官方组件 插件市场DCloud 插件市场 Vue 生态Taro 社区 React 生态团队要求需要专门小程序开发经验推荐具备 Vue 经验推荐具备 React 经验适合场景只做微信端、性能要求高、核心业务多端复用、团队熟 Vue、需要 H5/App多端复用、团队熟 React、复杂交互业务需要重点关注的是“微信新能力跟进”这一项。小程序平台会不定期发布新组件、新 API例如新的分享能力、新的硬件调用接口等。原生项目可以在能力开放后立刻接入uni-app 和 Taro 则需要等待框架侧把对应能力封装好或者在框架里通过条件编译直接写原生小程序代码来绕过但那样就破坏了跨端一致性等于为个别能力写平台特化代码。5. 常见问题与排查思路框架选型前试跑几个有代表性的 Demo 往往比读文档有效。下面列的是三种技术栈下最容易踩中的问题很多都来自开发者社群的真实求助。5.1 “uni-app 的 scroll-view 高度算不对内容不滚动”这是一个非常典型的问题。在 uni-app 里实现多 Tab 固定区域滚动常见写法是外层 flex 布局内容区域用scroll-view。很多人会遇到scroll-view即便设置了scroll-y内容超出后依然不滚动或者 scroll-view 直接撑开了整个页面。导致这个问题的根本原因是scroll-view需要明确高度约束不能依赖内容撑开。你可以给它一个固定高度也可以让它的父容器变成 flex 子项通过 flex 布局分配剩余高度。推荐做法不让scroll-view自己算高度而是通过布局“挤出”它的可用高度。以下示例演示如何解决主界面中scroll-view自适应剩余高度的问题template view classpage view classheader !-- 顶部固定区域 -- /view scroll-view classscroll-area scroll-y view v-for(item, index) in list :keyindex classlist-item {{ item }} /view /scroll-view /view /template style .page { display: flex; flex-direction: column; height: 100vh; /* 让页面占据视口高度 */ overflow: hidden; } .header { height: 200rpx; flex-shrink: 0; background: #f5f5f5; } .scroll-area { flex: 1; /* 占据剩余高度 */ min-height: 0; /* 关键允许子容器收缩到内容高度以下 */ overflow: hidden; } .list-item { height: 100rpx; line-height: 100rpx; border-bottom: 1px solid #eee; } /style关键点在于三处page高度设为100vh然后用overflow: hidden杜绝页面级滚动。scroll-view作为 flex 子项设置flex: 1让布局系统把剩余高度分给它。min-height: 0允许 flex 子项收缩到内容高度以下否则部分浏览器/小程序环境会按内容最小组件尺寸计算scroll-view依然无法触发滚动。如果你不用 flex 布局也可以用onPageScroll或IntersectionObserver动态计算剩余高度并赋给scroll-view但 flex 方案逻辑更少也更易维护。5.2 “scroll-view 已滚动到底部但普通 view 中的内容滑不动”另一个高频问题是页面拆成两个区域一个顶部是普通view一个是scroll-view。用户希望普通view里的内容滚动到最顶但手势操作被scroll-view拦截普通 view 一直没有滚动。这个问题的根因和 5.1 类似普通view天然不产生滚动内容超出后会被裁剪或直接撑开页面。如果你需要让页面里一个普通view内容也能“滑动到最顶端”建议改用scroll-view并设置scroll-y和明确高度或者直接使用页面级onPageScroll滚动不去做内嵌滚动如果这段内容只是长列表可以使用page-meta配合页面原生滚动。以下是一个让普通 view 中的长内容滚动到最顶端的scroll-view方案template view scroll-view classarticle-scroll scroll-y view classarticle-content !-- 长内容 -- /view /scroll-view view classgo-top clickscrollTop回到顶部/view /view /template script setup const articleScroll ref(null) function scrollTop() { // 方案一直接用 scroll-view 的 scroll-top 属性 // 方案二通过 SelectorQuery 拿到 scroll-view 节点并调用 scrollTo const query uni.createSelectorQuery() query.select(.article-scroll).node((res) { if (res res.scrollTo) { res.scrollTo({ top: 0, duration: 300 }) } }).exec() } /script方案一在该示例中更直接页面里绑定一个scroll-top变量点击后置 0 即可。不过需要留意的是scroll-top在连续点击时需要先置一个非 0 值再置 0否则可能因为值未变化而不触发事件。const scrollTopValue ref(0) function goTop() { scrollTopValue.value 1 nextTick(() { scrollTopValue.value 0 }) }在使用跨平台框架时遇到这类惯性滑动、滚动监听、吸顶问题建议先回退到原生小程序思维想一想这个能力在微信小程序原生环境里是怎么做的想清楚了再套框架的 API排错会轻松很多。5.3 “Taro 项目引入 React 库时浏览器 API 报错”Taro 3 支持 React 生态但并不是所有 React 库都能在小程序环境正常工作。很多 UI 库、工具库都直接或间接依赖window、document、navigator等浏览器对象小程序运行环境没有这些对象就会报 undefined 错误。排查步骤判断报错库是纯逻辑库还是 DOM 库。纯逻辑的如 lodash、dayjs 通常没问题。如果依赖了浏览器 API在小程序里不能直接用。同类能力优先选 Taro 官方或社区封装好的库。自己封装时使用process.env.TARO_ENV判断环境在不同端差异化实现。import { getSystemInfoSync } from tarojs/taro function getSafeAreaTop() { // 兼容 H5 和小程序的取值方式差异 if (process.env.TARO_ENV h5) { return window.innerHeight } const info getSystemInfoSync() return info.safeArea ? info.safeArea.top : 0 }5.4 “uni-app 项目如何用 Android Studio 做原生打包”“uni-app x”方向或部分使用原生插件的场景可能会接触到 Android Studio 原生工程。HBuilderX 自带云打包能力但如果要本地接入原生 SDK比如集成某个原生统计 SDK、音视频 SDK就需要在 Android Studio 中把 uni-app 的离线打包资源与原生工程合并。常规步骤大体是在 HBuilderX 中生成 App 资源选择“离线打包”相关选项。使用 DCloud 提供的 Android 离线打包 SDK把资源放进 Android 工程。在 Android Studio 中配置签名、包名对应关系。编译生成 APK。以上流程涉及较多原生工程细节且不同版本的 SDK 打包方式有差异执行时应以 DCloud 官方离线打包文档为准。对于纯前端团队来说这一步的成本往往被低估项目排期时要注意预留原生联调时间。5.5 原生小程序工程化之后还有必要用跨端框架吗这个问题经常被拿来讨论。如果团队已经有成熟的原生小程序工程化体系使用 TypeScript、ESLint、单元测试、CI/CD 构建发布再引入跨端框架并没有想象中的收益。跨端框架的核心收益是“一端代码多端运行”如果实际业务就只有微信端原生的开发和维护体验依然是最直接的。但反过来团队一个小程序产品要覆盖微信、支付宝、抖音或者同时要支撑 H5 端的营销页面坚持三套原生代码就意味着三倍的开发排期和三倍的 Bug 修复成本。这种情况下选择 uni-app 或 Taro 的长期收益会大于技术上的额外开销。6. 性能对比与优化边界6.1 首次渲染与包体积差异小程序平台对包体积有严格限制主包通常限制在 2MB 左右。微信原生空项目的包体积非常小只有几 KB 到几十 KB。uni-app 和 Taro 项目因为框架运行时、编译器注入的公共代码包体积会比同样功能的原生项目大。uni-app 空项目编译到微信小程序包体通常会增加几十 KB 到几百 KB具体取决于使用的组件和 API。Taro 3 由于内置 React 运行时基础体积相对更大这也是 Taro 社区优化包体时经常提到的点。两者都支持分包加载和按需注入实际生产项目中可以通过合理拆分页面、将非核心页面放入分包、把公共依赖提取到公共 chunk 等方式控制主包体积。6.2 长列表渲染对比长列表是两类框架差异最明显的性能场景。原生小程序的wx:for配合setData更新需要注意避免全量更新。优化手段包括把列表拆成子组件只更新变化项的数据。使用wx:key提高 diff 效率。使用虚拟列表或回收节点的方式控制实际渲染的节点数量。uni-app 中同样要遵循上面的思路v-for的 key 必须给setData的使用还是遵守原生逻辑避免一次性传入大数组。Taro 3 的长列表由于有 React diff 这一层每次状态更新都对组件树做一次协调列表项数量越多diff 必然越慢。实际项目中经常要引入虚拟列表方案Taro 官方提供了VirtualList组件社区也有tarojs/components中的虚拟列表或者自己按滚动位置懒加载。6.3 减少跨端框架性能损耗的通用手段无论选择 uni-app 还是 Taro下面几条性能优化思路都是通用的减少不必要的页面级setData/setState状态更新粒度尽量细化到组件级别。避免渲染大数据量后台分页 前端懒加载前端只维护可视区数据。高频事件手动节流比如滚动、触摸、输入框实时搜索等场景。静态资源放到 CDN图片设置合适的宽高避免图片加载引起的布局抖动。复杂计算不要放在渲染流程里用computedVue或useMemoReact做缓存。将纯展示型组件拆出来避免父组件状态更新导致所有子组件全部重复渲染。7. 团队成本与选型决策建议7.1 团队技术栈决定第一优先级选型首先要看团队里面的人会什么。如果团队主力是 Vue 技术栈那么 uni-app 的学习成本最低团队成员可以很快把已有 Vue 组件的样式、结构迁移过来。如果团队主力是 React 技术栈Taro 的 React 写法接受度会很高React Hooks 的开发模式可以直接使用。如果团队本来就长期做小程序原生开发且团队成员对 WXML 的模板语法、setData 的性能约束、小程序生命周期如数家珍那么没有特别强的理由去切换到跨端框架。一个残酷的现实是跨端框架出现的大部分场景并非技术上的最优解而是团队“想要一套代码交付多个端”这个业务目标的妥协产物。认清这一点才不容易在后续的 Bug 排查中被框架限制磨掉耐心。7.2 多端复用程度评估选型前先回答几个问题产品是否必须同时上线微信、支付宝、抖音等多个小程序平台各平台之间是“完全一致”还是“各自有差异化功能”H5 和 App 是否也在产品路线图内如果答案是“只做微信小程序最多以后试试支付宝”跨端框架的收益率很低反而因为平台差异化能力要用条件编译去适配写起来比原生更别扭。如果答案是“微信 支付宝 抖音三端同步每端还要适配平台的登录和支付”那么用跨端框架统一写业务逻辑再通过环境判断处理平台差异效率会高很多。业务上多端复用程度越高跨端框架的价值越大。单一平台项目原生的“直给”优势反而更突出。7.3 原生能力和第三方 SDK 适配成本每家平台都有自己的原生能力例如微信的开放数据域、运动数据、NFC、蓝牙支付宝的芝麻信用、身份认证抖音的各种端内能力。这些能力的接入方式和技术规范差异较大。原生项目中直接调用平台 API 最方便。跨端框架中如果框架已经封装了同类 API可以直接使用如果没封装通常需要条件编译 平台判断 调用平台原生方法的方式来实现这会导致代码的跨端性下降。对第三方 SDK如统计、推送、客服、音视频的支持也要提前调查。很多第三方 SDK 只提供了微信小程序版本或原生 App 版本直接套用到 uni-app 或 Taro 项目中往往不行。选型前最好把项目计划中用到的第三方服务列出来逐一查证在对应框架中的接入方式、官方支持程度和社区案例数量。7.4 长期维护与团队招聘小程序开发不是一个“写完就结束”的事。上线之后的迭代、Bug 修复、平台升级适配才是长久的维护成本。原生项目长期维护最大的风险是“知识封闭”新成员要重新学习小程序平台规则。但小程序平台的规则本身就相对稳定一旦熟悉后反而很顺畅。uni-app 项目的维护风险在于随 DCloud 的发展方向波动。DCloud 推出的 uni-app x 等新方向说明产品路线可能随时调整对这些商业产品的长期依赖需要评估。Taro 项目则受京东前端团队的开源维护节奏影响版本升级对项目稳定性的影响也需要团队有人长期跟进社区变化。招聘维度上不同技术栈的候选人供给情况差别很大。小程序原生开发的候选人大多来源于业务项目培养Vue 和 React 候选人基数更大招到能写 uni-app/Taro 的人更容易一些但深入掌握框架原理的人占比不高。多数项目需要的并不是框架作者级别的深度而是能根据报错信息快速定位并在小程序原生机制层面找到解法的人。8. 实操型选型清单为了让选型从讨论进入决策状态建议团队基于下面的清单逐项打分再结合项目时间与人员情况做最终决定。评估项原生小程序uni-appTaro产品只在微信端运行强烈推荐使用收益不突出收益不突出团队熟悉 Vue不影响首选考虑也可以使用 Vue 3 版本团队熟悉 React不影响学习成本偏高首选考虑需要多端小程序需要写多套最优选优选项之一还需要 H5 落地页需另做项目一套代码出 H5一套代码出 H5还需要 App需另做原生 App有 App 端方案可通过 RN 扩展项目性能极其敏感最优选次优有性能风险项目逻辑复杂、组件复用高模板写法受限模板写法受限React 表达力更好表格打分后注意一点技术选型不能只看当前项目的排期。如果公司未来有统一前端中台的战略跨端框架的统一收益会放大。如果只是接一个临时外包小程序且未来大概率不会继续迭代那么原生开发可能是最干净的交付方式。9. 三条实战建议与收尾最后写三条可以直接落地的工程建议。第一不要把跨端框架当成万能药。它解决的是多端代码复用问题而不是解决团队技术能力问题。一个连小程序原生 data 传递和 setData 性能机制都没搞清楚的团队不管换到 uni-app 还是 Taro都会在性能和兼容性上反复踩坑。建议无论最终选什么团队中至少有一两个成员能独立阅读原生小程序编译产物知道报错发生在哪个环节。第二选型阶段一定要做对比 Demo。不仅做页面展示 Demo更要做网络请求、登录态、列表滚动、条件渲染这些高频率业务场景的 Demo把三套代码在微信开发者工具里的编译产物都打开看一遍理解每一行报错来自运行时还是编译期。这个环节花的时间不会白费。第三发现框架解决不了的问题时果断使用条件编译兜底。uni-app 的条件编译可以用#ifdef标记Taro 可以用process.env.TARO_ENV做环境判断必要时直接写原生小程序代码。跨端框架的价值是提高效率但不要让框架的抽象边界绑架业务。关键路径上直接调用原生能力写一点平台专属代码比绕来绕去维护一个“看起来跨端但哪端都跑不顺”的抽象更明智。小程序开发技术的迭代速度不慢今天基于 Vue 3 的 uni-app 和基于 React 的 Taro 3明天可能就会被新的框架方案冲击。与其纠结“哪个一定最好”不如回到你自己的项目约束里回答你的目标平台是哪些团队会什么性能红线在哪里维护周期有多长这三个问题有了明确答案框架选择基本就出来了。