uni-app 条件编译
这是 uni-app 最核心、也最容易被新手忽略的知识点。条件编译,一套代码里针对不同平台写不同代码,编译时只保留当前平台的部分。
一句话理解,代码里标记 #ifdef H5 的片段只会在编译 H5 端时存在,其他端会被直接删除,编译产物里根本看不到。
为什么需要条件编译
uni-app 已经封装了绝大多数跨端能力,但平台差异永远存在,典型场景:
- H5 端能用的网页能力(如键盘事件、localStorage),小程序里没有
- App 端能调用的原生能力(如推送、本地通知),网页里没有
- 微信小程序的分享、订阅消息,其他平台没有
- 同一功能各端 API 不同(如登录授权方式)
处理这些差异,不要试图用一套逻辑硬兼容所有端,条件编译是解决差异化最有效的手段,只在需要的地方为特定平台写专属代码。
平台标识速查
| 平台标识 | 对应平台 |
|---|---|
H5 |
网页端 |
APP-PLUS |
App(iOS、Android、鸿蒙) |
MP-WEIXIN |
微信小程序 |
MP-ALIPAY |
支付宝小程序 |
MP-BAIDU |
百度小程序 |
MP-TOUTIAO |
抖音小程序 |
MP-QQ |
QQ 小程序 |
MP |
所有小程序平台 |
VUE3 |
Vue3 编译版本 |
记住最常用的三个就够起步了,H5、APP-PLUS、MP-WEIXIN。
三种语句
| 语句 | 含义 |
|---|---|
#ifdef |
仅在该平台存在时编译 |
#ifndef |
该平台不存在时编译 |
#endif |
结束条件编译 |
两个平台同时满足用 ||,同时满足用 &&:
// 微信 或 支付宝 小程序都编译
// #ifdef MP-WEIXIN || MP-ALIPAY
// #endif
在 JS 中使用
注释语法,// 开头:
// #ifdef H5
console.log('这段代码只会在网页端编译')
// #endif
// #ifdef APP-PLUS
console.log('这段代码只会在 App 端编译')
// #endif
// #ifndef H5
console.log('非网页端都会编译这段(小程序、App 等)')
// #endif
实战例子,在 App 端调用原生功能,网页端给提示:
function shareToFriend() {
// #ifdef APP-PLUS
plus.share.sendWithSystem({
content: '分享内容',
success() {}
})
// #endif
// #ifndef APP-PLUS
uni.showToast({ title: '当前平台不支持分享', icon: 'none' })
// #endif
}
在模板中使用
HTML 注释语法,<!-- -->:
<template>
<view class="page">
<!-- #ifdef H5 -->
<view class="web-tip">网页端专属提示</view>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<button open-type="share">分享给微信好友</button>
<!-- #endif -->
</view>
</template>
微信小程序端打包后,页面里只有分享按钮,没有网页提示;H5 端正好相反。
在样式中使用
CSS 注释语法,/* */:
.container {
padding: 20rpx;
}
/* #ifdef H5 */
.container {
max-width: 600px; /* 网页端限制最大宽度,居中显示 */
margin: 0 auto;
}
/* #endif */
同一条规则写两遍也没问题,编译时会把不属于当前平台的块整个删掉。
在 pages.json 中使用
配置文件里同样支持,注意这里用的是普通注释写法:
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
// #ifdef APP-PLUS
,"navigationBarBackgroundColor": "#FF0000"
// #endif
}
}
]
}
提示:在 pages.json 里用条件编译时,要注意 JSON 的逗号位置,容易写成语法错误,不熟练时建议尽量少在配置里用。
按平台拆分文件
除了在文件内部做条件编译,还可以整个文件按平台拆分。文件名带平台后缀,编译到对应平台时优先使用:
pages/
├── login/
│ ├── login.vue # 通用登录页
│ ├── login-h5.vue # 网页端专用(编译 H5 时替换 login.vue)
│ └── login-mp-weixin.vue # 微信小程序专用
适合平台差异特别大的页面,比如登录方式完全不同的场景。能拆文件就不写一堆 #ifdef,可读性更好。
常见误区
误区一:条件编译可以随意嵌套
每个 #ifdef 必须配一个 #endif,注释必须完整,嵌套时要小心层级,写错会编译报错或者代码莫名消失。
误区二:把业务判断写成条件编译
条件编译是编译期处理,用户运行时代码已经定死。if 判断是运行期处理,用户还能动态改变。到底部选项卡显示哪个、用户有没有登录,这些必须用 if,不是条件编译。
误区三:以为条件编译能替代 API 适配
条件编译只解决「这段代码属于哪个平台」,平台共有的能力直接用 uni. API 让框架处理,不要到处 #ifdef,能不用就不用的代码最干净。
综合示例:一个方法适配三端
做一个「提醒用户」功能,App 端弹原生通知,微信小程序弹确认框,网页端直接提示:
function remind(message) {
// #ifdef APP-PLUS
plus.push.createMessage(message, 'notice', { title: '待办提醒' })
// #endif
// #ifdef MP-WEIXIN
uni.showModal({
title: '提醒',
content: message,
showCancel: false
})
// #endif
// #ifdef H5
uni.showToast({ title: message, icon: 'none' })
// #endif
}
三个平台打包后,各自只会留下对应的一段代码,另一个平台的人根本不会看到别的端逻辑。
总结
| 知识点 | 要点 |
|---|---|
| 为什么需要 | 平台差异客观存在,条件编译是解决差异化的最有效手段 |
| 平台标识 | H5、APP-PLUS、MP-WEIXIN 最常用 |
| 语句 | #ifdef 存在时编译 / #ifndef 不存在时编译 / #endif 结束 |
| 使用位置 | JS(//)、模板(<!-- -->)、CSS(/* */)、pages.json |
| 文件级拆分 | login-h5.vue 这种带平台后缀的文件 |
| 常见误区 | 不是运行时判断,不能乱嵌套,能不用就不用 |
一句话总结:条件编译是 uni-app 处理平台差异的终极武器,用注释标记代码归属,编译时各取所需,不要在业务逻辑里硬兼容所有平台,分不开的才交给条件编译。