一、背景:组件能不能复用,平台说了算
很多人以为“uniapp 能跨端,组件就能通用”,但当项目一复杂,真相浮出水面:
UI 看起来一样,但行为差异巨大
- 小程序的 input 无法聚焦控制
- App WebView 中跳转带参数失效
- H5 上的滚动行为与小程序不一致
广告平台项目中,我踩了这些坑,也设计了解决策略。
二、真实案例:筛选组件在多端的分裂
通用筛选组件结构如下:
<template>
<view class="filter-wrapper">
<picker :range="options" @change="onSelect" />
</view>
</template>
🧨 问题:
- H5 页面
picker样式差异大,无法统一 - 微信小程序
picker触发机制不同,必须选中后失焦才响应 - App 中
picker动画出现卡顿,影响体验
三、解决策略一:平台能力注入 + 组件变体
为每个平台定义“行为包”:
export const usePlatformPicker = () => {
if (process.env.UNI_PLATFORM === 'mp-weixin') {
return { type: 'picker', fix: wechatFix }
}
if (process.env.UNI_PLATFORM === 'h5') {
return { type: 'select', fix: h5Fix }
}
return { type: 'native-select' }
}
在组件中使用:
<component :is="platformPicker.type" @change="onChange" />
四、解决策略二:抽象业务逻辑为 hook
组件难以复用时,抽象“行为”比抽象“UI”更靠谱:
// useFilter.ts
export const useFilter = () => {
const filterValue = ref('')
const applyFilter = (val) => {
filterValue.value = val
fetchData({ keyword: val })
}
return { filterValue, applyFilter }
}
各平台只需绑定不同 UI 实现,逻辑一致。
五、解决策略三:平台指令差异封装
例如 input 聚焦 bug(iOS 小程序中点击聚焦失败)
onMounted(() => {
if (process.env.UNI_PLATFORM === 'mp-weixin') {
nextTick(() => {
setTimeout(() => inputRef.value?.focus(), 300)
})
}
})
六、解决策略四:平台条件编译
使用条件编译标签:
<!-- #ifdef MP-WEIXIN -->
<picker />
<!-- #endif -->
<!-- #ifdef H5 -->
<select />
<!-- #endif -->
虽然降低复用性,但能精细控制差异。
七、组件复用的边界与思考
当业务复杂、端能力差异大, “100%复用”不现实,适配成本比重构还高。
我在团队中提出“通用逻辑抽象 + 样式灵活实现”的设计法则:
- UI 可分叉,但行为统一
- 数据格式、响应流程一致
- 所有差异明确封装,避免业务层感知
八、总结:平台差异不可怕,可怕的是“误以为没差”
我在广告投放平台跨端开发中踩过的坑,最终都化成了系统性的组件适配策略。