你以为小程序组件就能复用?复杂业务下的“代码适配黑洞”

85 阅读2分钟

一、背景:组件能不能复用,平台说了算

很多人以为“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 可分叉,但行为统一
  • 数据格式、响应流程一致
  • 所有差异明确封装,避免业务层感知

八、总结:平台差异不可怕,可怕的是“误以为没差”

我在广告投放平台跨端开发中踩过的坑,最终都化成了系统性的组件适配策略。