uniapp条件编译怎么用?我拿支付场景做了个跨端兼容实战

2026-08-17 0 520

一个用uniapp写的项目,同时要出微信小程序和H5版本。最开始觉得uniapp都能编译过去,应该没啥问题。结果遇到支付功能,小程序要用wx.requestPayment,H5得引入第三方支付SDK,两者参数完全不同,甚至回调机制都是两套。我一开始在业务代码里写各种运行时判断:if (platform === ‘weixin’) … else …。后来越加越多,连调接口的URL都不一样,代码乱到没法维护。

后来单位老前辈提了一句:“干嘛不用条件编译?” 我这才去翻了文档。用完之后想说:真香。今天就把我那次的改造过程写出来。

条件编译到底是什么?

简单讲,条件编译是“在编译阶段”根据当前打包的平台,把不需要的代码直接从源文件中剔除。它和普通的if判断完全是两码事:if是运行时判断,所有平台的代码都保留在包里;条件编译后,你写在小程序里的那段代码,在打H5包时根本不存在了。这样既能避免执行错误,也能减小包体积。

uniapp里的写法无非两种:#ifdef 表示“如果定义了某平台就保留”,#ifndef 表示“如果没定义某平台就保留”。最后用#endif结尾。要注意的是,在模板、脚本、样式的注释写法各有不同,别写混了。

基本语法一览

在script中,这样写:

// #ifdef H5
console.log('这是H5平台')
// #endif

// #ifndef MP-WEIXIN
console.log('不是微信小程序平台')
// #endif

在template里,要写在html注释中:

<!-- #ifdef H5 -->
<view>H5才显示的视图</view>
<!-- #endif -->

在style中,用css注释:

/* #ifdef MP-WEIXIN */
.button { width: 200px; }
/* #endif */

很多人第一次用容易忘记结束符,或者把#ifdef写成了#if defined,这些都要注意。

我做的支付案例

当时我的目录结构是这样:

src/
├── api/
│   └── pay.js
├── pages/
│   └── order/
│       └── pay.vue

最初我把所有平台的支付逻辑都堆在pay.vue里面,看起来就是这个样子:

// #ifdef MP-WEIXIN
uni.requestPayment({
    provider: 'wxpay',
    orderInfo: res.data.payParams,
    success: () => {
        uni.showToast({ title: '支付成功' });
    }
});
// #endif

// #ifdef H5
// 假设H5用的支付宝的SDK
window.AlipayJSBridge.call('tradePay', {
    orderStr: res.data.orderStr
}, (result) => {
    if (result.resultCode === '9000') {
        uni.showToast({ title: '支付成功' });
    }
});
// #endif

虽然能跑,但这段代码放在一个页面里实在难看,尤其是支付成功后还要跳转不同页面、处理不同参数,混在一起我自己都不想看。后来我抽了三个文件:

src/
├── api/
│   ├── pay.js
│   ├── pay.mp.js
│   └── pay.h5.js

然后在pay.js里做基础封装,再通过条件编译引用不同平台的实现:

import base from './pay.js';

// #ifdef MP-WEIXIN
import mpPay from './pay.mp.js';
// #endif

// #ifdef H5
import h5Pay from './pay.h5.js';
// #endif

export default {
    pay(params) {
        // #ifdef MP-WEIXIN
        return mpPay.pay(params);
        // #endif

        // #ifdef H5
        return h5Pay.pay(params);
        // #endif
    }
}

这样在页面里只需要调用统一的pay(params),剩下的事各自平台自己处理。改动就很小,而且以后要加App端,再加一个pay.app.js,然后加一行条件编译就行,完全不影响其他地方。

模板里的条件编译:处理不同平台的UI差异

除了逻辑,有时候界面也需要不同。比如支付页底部有个“使用优惠券”按钮,微信小程序里要用button open-type="contact",H5上却是个普通按钮,点击唤起客服聊天。遇到这种情况,模板条件编译也能直接隔离。

<!-- #ifdef MP-WEIXIN -->
<button open-type="contact">联系客服</button>
<!-- #endif -->

<!-- #ifdef H5 -->
<button @click="contactH5">联系客服</button>
<!-- #endif -->

没有条件编译之前,我得在数据里定义isWeixin,然后v-if判断,代码又长又丑。现在这种注释式写法,打包时直接留下对应平台那块,清爽多了。

踩过的几个坑

1. 条件编译是编译期,不是运行期

一开始我犯了个错,我在条件编译里写了一个变量,然后在外部试图访问它,结果报错找不到变量。原因是那段代码在另一个平台被剔除了,根本不存在。所以如果你需要定义公共变量,把它放在条件编译外面。

2. 嵌套条件编译很容易乱

比如你想同时兼容小程序和H5,但又要排除App,写成这样:

// #ifdef MP-WEIXIN || H5
console.log('小程序或H5');
// #endif

这个语法其实是支持的,但要注意不要和#ifndef混用产生逻辑冲突。我建议能拆分就拆分,别一个条件里写太多。

3. template里的条件编译注释不能加空格

<!-- #ifdef H5 --> 这种写法是允许的,但如果你在 #ifdef 前多了空格,某些版本可能识别不了。最好严格按照官方示例来,别自己加`#ifdef H5`里面带空格。我试过<!-- #ifdef H5 -->是合法的,但注释结束符-->前面有没有空格都行。

4. 样式条件编译最好配合使用

有时候某个平台需要特殊间距,我会在style里写:

/* #ifdef MP-WEIXIN */
.pay-button { margin-top: 20rpx; }
/* #endif */

但是注意:这不会自动加上选择器权重,如果你的基础样式写在普通选择器里,条件编译的样式没有「更晚加载」的优势,可能会被覆盖。解决办法是把条件编译的样式写在后面,或者提升权重。

5. 微信小程序的特殊变量不能乱用

在小程序里可以用wx全局变量,在H5里没有。如果你在条件编译里用了wx.getStorageSync,并且打包到H5,这段代码会被剔除,没问题。但如果你不小心在外面引入了wx的API,照样报错。条件编译不是万能护身符,业务代码里还是得注意平台差异。

什么时候不该用条件编译

如果只是某个平台的小差异,比如字体大小、颜色值,直接用CSS变量或者平台类名就行,别搞太多条件编译,代码反而更难阅读。条件编译最好用于那些“完全不同的实现”或者“不同平台的API调用”上。

另外,如果你的项目将来想发布到小程序、H5、App,条件编译是必须的。但建议在每个使用条件编译的地方加一行注释,说明为什么需要,比如“H5支付不出App,这里单独处理”,不然同事看到这段代码容易骂人。

总结

自从用了条件编译,我那个支付页面的代码量少了一半,而且排查问题时一眼就能看到当前平台真正执行的是哪一段。uni-app本身已经做了很多跨端兼容,但总有一些平台不可调和的差异,这时候条件编译就是最后的底牌。

如果你也遇到“H5好好的,小程序死活不对”或者“小程序能行,APP又不行”的情况,不妨检查一下是不是该做平台隔离。别再用if了,试试条件编译,真的一身轻。

uniapp条件编译怎么用?我拿支付场景做了个跨端兼容实战
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

版权声明:
本站资源有的来自互联网收集整理,本站纯免费分享提供学习使用,如果侵犯了您的合法权益,请发送邮件1506151422@qq.com联系,将会及时下架删除。
本站资源仅供研究、学习交流之用,免费开源项目不代表完全可商用,若商业用途请先咨询开发企业能否商用,否则产生的一切后果将由下载用户自行承担。
原创板块未经允许不得转载,否则将追究法律责任。

淘吗网 uniapp uniapp条件编译怎么用?我拿支付场景做了个跨端兼容实战 https://www.taomawang.com/web/uniapp/2558.html

常见问题

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务