微信小程序和 H5 的 API 差异客观存在:小程序靠 wx.login 拿 code,H5 通常用设备号或账号密码;小程序能直接调扫码,H5 只能跳转链接。条件编译是 UniApp 官方推荐的解法:编译器按平台裁剪代码,一套源码多处发布。

实现思路

以 // #ifdef 与 // #ifndef 包裹差异代码块,后面跟上平台标识 MP-WEIXIN 表示微信小程序、H5 表示网页端;同一业务函数里写两套实现,各自调用对应平台 API,编译时只保留当前平台分支。

登录差异处理

// utils/auth.js
export function login() {
    // #ifdef MP-WEIXIN
    uni.login({
        provider: "weixin",
        success: async (res) => {
            const data = await http.post("/auth/wechat-login", {
                code: res.code
            });
            saveToken(data);
        }
    });
    // #endif

    // #ifdef H5
    const deviceId = getDeviceId();   // 取浏览器指纹
    http.post("/auth/guest-login", { deviceId }).then((data) => {
        saveToken(data);
    });
    // #endif
}

扫码降级

小程序用 uni.scanCode 直接调起摄像头,H5 不支持该能力,改为引导用户输入码或复制链接。

export function scanCode() {
    // #ifdef MP-WEIXIN
    uni.scanCode({
        success: (res) => handleCode(res.result),
        fail: () => uni.showToast({ title: "扫码失败", icon: "none" })
    });
    // #endif

    // #ifdef H5
    uni.showModal({
        title: "提示",
        content: "当前浏览器不支持扫码,请输入桌台码",
        editable: true,
        success: (r) => {
            if (r.confirm && r.content) handleCode(r.content.trim());
        }
    });
    // #endif
}

模板里的条件编译

条件编译同样适用于 template 与 css,例如 H5 顶部做沉浸式适配、小程序显示胶囊占位。

// template 内写法
// #ifdef H5
<view class="status-bar"></view>
// #endif

// #ifdef MP-WEIXIN
<view class="nav-capsule">自定义导航</view>
// #endif
/* style 内写法 */
/* #ifdef H5 */
.page { padding-top: 44px; }
/* #endif */

封装统一出口

为避免页面到处写 #ifdef,把平台差异收敛到 utils 层统一导出,业务页面只调用同名字段。

// utils/platform.js
export const isMp = () => {
    // #ifdef MP-WEIXIN
    return true;
    // #endif
    // #ifndef MP-WEIXIN
    return false;
    // #endif
};

需要注意

  • 条件编译写在注释里,// #ifdef 前必须有双斜杠且保持固定写法,关键字不能被变量拼接;
  • 模板与样式里的条件编译用 HTML 注释 / CSS 注释包住,写法不同不要混用;
  • 条件编译是在编译期裁剪,无法在运行时切换平台,调试时需分别运行到各端预览;
  • 真机上验证微信登录,需要在微信公众平台配置业务域名与 AppSecret。

小结

条件编译是 UniApp 跨端开发的核心武器,把差异点收口在工具层,业务代码保持平台无关,两端的维护成本基本趋近于一套。