uniapp 多端兼容指南

开发过程中需要编译到多端查看效果

一、基础

1.1 样式:

微信小程序 css 中无法直接使用本地资源图片,需要使用网络资源或不直接写在css中,详情参考 此处

.buy-tabs {
  font-size: 32rpx;
  /* 编译到微信小程序报错 */
  background-image: url('/static/images/employment/icon-buy.png');
}
/* 使用网络路径 或 在template 模板中使用动态 样式 style / :custom-style="{backgroundImage:"xx"}" */

不兼容的的css选择器

选择器 h5 安卓 ios 微信小程序 备注
:focus N N N N
:lang(language) Y N N N
* Y N N N -
:root Y N N N h5端的支持只能是在 app.vue 的 style 标签里写的或者 @import 的样式里才能用 :root
:enabled N N N N 类似于 :focus,可使用类似于 button:not([disabled]) 的方案代替
:checked N N N N :disabled

此外谨慎使用标签选择器p{}和复杂度后代选择器.a>.b,小程序对这些的支持度不高

微信小程序 非自定义组件不支持 v-bind=”$attrs”

<!-- ✔ -->
<wd-navbar v-bind="$attrs" />
 <!-- ✔ -->
<hk-area-selector v-bind="$attrs" />
<!-- × -->
<view v-bind="$attrs" />

微信小程序对空值的处理

页面中空值在小程序会转换成字符串 undefinde -> “undefinde” , 这个问题在路由传值或者接口传值中也会存在!

v-deep 写法不生效问题

<template>
  <view class="root-view">
     <wd-search />
  <view>
</template>

<style lang="scss">
 .root-view {
   height: 100%;

   /* 正确写法,需要有“上下文” ,一个当前页面的 class 下写穿透 */
   ::v-deep .wd-search {
    background: #ff0
  }
   
 }

  /*  微信小程序上不生效的写法1 */
  /* ::v-deep .wd-search {
    background: #ff0;
  }
   */
  
/*  微信小程序上不生效的写法2  ,同理 deep()中也需要指定 */
  /* :deep() {
    .wd-cell__wrapper {
      height: 56rpx;
      align-items: center;
    }
  } */
  
</style>
<style lang="scss" scope>
  .root-view {
    --wot-segmented-item-bg-color: #ffffff;
  }
</style>

原子化class 避免使用’/‘ ‘'写法

<!-- //(x) 在微信小程序 /88rpx被直接忽略 -->
<view class="text-[36rpx]/88rp" />
<!-- 分开 -->
<view class="text-[36rpx] line-height-[88rpx]" />

部分组件库提供了 custom-class (如uview /wot) 的, class 需要使用 custom-class ; 否则编译到小程序会导致部分样式丢失

1.2 分包/资源:

微信小程序禁止在主包以及分包中引入其他分包的文件 (分包可引主包)

/* packB */ 
import { aFunc } form "@/pages-sub/packA/utils"  /* (x) */

/* pack-Main */ 
import { aFunc } form "@/pages-sub/packA/utils"  /* (x) */

/* packB */ 
import { aFunc } form "@/pages/utils"  /* (✔) */
import { aFunc } form "@/utils"  /* (✔) */

包大小优化

  • 大模块依赖/大组件 谨慎在主包以及涉及主包内引入,将业务拆分到分包中处理

1.3 页面传参:

小程序比较特殊,不同场景进入有差异

import { getRequest } from '@/utils/index'
// (1) 普通页面传参 page1.vue
 uni.navigateTo({
  url: 'page2?id=1&name=2',
})

// page2.vue
onLoad((opts) => {
// (1) 正常方式接收 
  const id = opts.id
// (2) 小程序上不同场景
  // 2.1 默认 (或者小程序卡片分享进入)
  const id = opts.id
// 2.2 扫描小程序码/小程序二维码进入 (.scene)
   if (opts.scene) {
       // opts.scene = "id=1"
				const result = getRequest(opts.scene = "id=1&name=2");
			  opts = result  // or opts.id = result.id
	  }
   const id = opts.id

  // 2.3 小程序普通链接 (.q)
  if (opts.q) {
       // opts.scene = "id=1"
				const result = getRequest(opts.scene = "id=1&name=2");
			  opts = result  // or opts.id = result.id
	  }
   const id = opts.id
})

二、组件/API

2.1 地图

正常情况下,无层级问题的地图场景,使用uni官方<map>组件;

如有层级问题,则需考虑多端兼容方案:

**1. 使用 组件,层级问题使用 cover-view 解决 **https://uniapp.dcloud.net.cn/component/cover-view.html#cover-view

<template>
  <cover-view>
    <cover-text>
      cover 方案中,所有需要比 map 高的层级都需要使用 cover 重构
    </cover-text>
  </cover-view>
  <map />
</template>

2.app端使用 renderjs 渲染,其他端使用 <map>组件 注 renderjs暂不支持鸿蒙 注意传参尽量使用与 map 组件相同的命名和参数,方便做条件编译https://uniapp.dcloud.net.cn/tutorial/renderjs.html#renderjs

<script lang="ts" setup>
  // #ifdef MP-WEIXIN || APP-HARMONY
  // renderjs 方案
  import MapMark from '../../pages/hk-amap/mark.vue'
  // #endif
  // #ifdef APP-PLUS || H5
  // 原生 map 方案
  import WebMapMark from '../../pages/hk-amap/web-amap.vue'
  // #endif
</script>

<template>
  <!-- #ifdef APP-PLUS || H5 -->
  <WebMapMark :marker-list="[{ lat: location_data.lat, lng: location_data.lng }]" />
  <!-- #endif -->
  <!-- #ifdef MP-WEIXIN || A -->
  <MapMark :latitude="Number(location_data.lat)" :longitude="Number(location_data.lng)" />
  <!-- #endif -->
</template>

2.4 获取定位信息

uni.getLocation 只有APP端会返回 address 信息,可以写一个方法针对其他平台调用逆地理编码拼接获取 address 信息,注意如果业务不需要 address 信息,建议直接调用 uni.getLocation 方法(逆地理编码api一般有配额限制)

<script setup>
import { getLocationAttachAddr } from '@/utils/map'
  
getLocationAttachAddr({
    type: 'gcj02',
    geocode: true,
    isHighAccuracy: true,
    success: (res) => {
      const { latitude, longitude, address } = res
      console.log('getDirection latitude, longitude, address', latitude, longitude, address)
    },
    fail: (err) => { console.error(err) },
  })
</script>

三、其他

3.1 平台功能差异

部分功能在特定平台本身就无法兼容或兼容方式差异非常大或体验很差;

APP 微信小程序 h5
webview 支持跳转以及实时交互
注意有层级问题
支持业务域名白名单内跳转;
不支持实时交互(需要页面返回或关闭才能收到message); 无法隐藏导航头且一定全屏显示;
支持跳转;不支持实时交互(需要额外处理不建议)
定位(uni.getLocation) 支持获取精确/模糊定位以及位置信息(address) 开通api能力后支持,位置信息(address)通过地理位置逆编码获取 https 或 local 环境下才支持获取定位;信息(address)通过地理位置逆编码获取
地图(map/renderjs) map/renderjs使用高德地图 map会编译成腾讯地图;如果用randerjs实现需要兼容使用map组件 map/renderjs使用高德地图
扫码(uni.scanCode) 支持且兼容 支持且兼容 不支持(替代方案有https://www.npmjs.com/package/html5-qrcode
录音(uni.getRecorderManager) 支持且兼容 支持且兼容 不支持(替代方案有https://ext.dcloud.net.cn/plugin?id=15717
分享 通过uni.share;需要开通对应的SDK能力(通常捆绑app签名) 只能通过 open-type=”share” + onShareAppMessage 触发分享,只能分享到小程序, 并且分享出去的形式只能是小程序卡片 要分享到微信,需接入wx-js-sdk 并且只支持在 微信内浏览器中使用(捆绑域名)
资源限制 如果是网络资源必须以http/https 开头;“//at.alicdn.com/t/c/font”此类会被识别成urlShame需要写完整 请求和资源必须是https并且在小程序后台配置 请求有可能跨域
plus能力 android/ios 支持 ;
鸿蒙next 暂不支持
不支持 android/ios 手机浏览器或webview打开的支持;微信浏览器未测试;
返回拦截(onBackPress) android支持返回键/手势/uni.navigateBack, onBackPress无法拦截到ios的’侧滑返回’,可考虑禁用侧滑 onBackPress只支持uni.navigateBack onBackPress只支持uni.navigateBack
引导地图导航(@/utils/map :toMapApp) 支持 建议用uni.openLocation 没试过
选择文件(非媒体文件) 通过plus 调用MediaStore 或者 去应用市场找插件(l-file?) 只能选微信聊天文件 wx.chooseMessageFile 支持 uni.chooseFile
跳转企业客服 通过 plus.share服务,openCustomerServiceChat 打开指定企业微信客服 openType: ‘contact’ 跳转的是 小程序后台配置的客服 未测试

3.2 UI设计

通常问题出现在 小程序平台等,与移动端基础样式有差异的,需要兼容或者需要UI针对特定平台设计;

胶囊遮挡导航头问题

  • 分享自定义导航头组件处理

底部/顶部 安全区域

  • safe-area-inset-top:安全区域距离顶部边界的距离
  • safe-area-inset-bottom:安全距离底部边界的距离
  • --status-bar-height:系统状态栏高度

https://uniapp.dcloud.net.cn/tutorial/syntax-css.html#css-%E5%8F%98%E9%87%8F

.header {
 // 顶部状态栏高度
  padding-top: var(--status-bar-height);
}
.resume-footer {
  position: fixed;
  left: 0;
  bottom: 0;
  // 底部留出安全区域
  padding-bottom: env(safe-area-inset-bottom);
}

— 2025 / 12/18