返回博客

抄了同文件 sibling 却仍失败:输入象限没对齐才是真根因

调试复杂 UI bug 时有一条经验法则:先找同文件里已经 working 的相似实现直接抄,比从头理论推断快 10 倍。这条规则本身没错,但我在一次微信小程序弹窗 bug 的三轮修复中踩到了它的隐藏陷阱——抄的对象选对了,姿势也对,但仍然在真机上翻车。

问题不在「抄」,在于没有先问一句:sibling 的「工作」究竟在哪些输入场景下被验证过?

现象

一个 C 端小程序的内容弹窗(高度约 60vh、内容可长可短),要求弹窗内部可滚动、背景页面锁死不滚动。

第一轮用自定义遮罩 + catchtouchmove + view overflow-y 的四件套实现,真机失败。

第二轮换思路:同文件已有一个标签选择弹窗(tag-popup),用 van-popup + scroll-view 实现,模拟器和真机都能正常滑动。完美 sibling,直接抄。

把 FAQ 弹窗改成同款结构后——长内容可滑 ✅,但短内容时用户手指落在 scroll-view 外的 padding 区向下划,touch 事件穿透到底层页面,背景继续滚 ❌。

根因

tag-popup 的内容是标签列表,标签项总是很多,始终超过弹窗高度,所以 scroll-view 始终撑满了 popup 可用区域。它从未遇到过「内容比弹窗矮」的情况——短内容象限在 sibling 的业务场景里根本不存在。

照抄结构只对齐了 sibling 已验证的象限(长内容),而未验证的象限(短内容)继续翻车。

坑:sibling 的「工作」只在它自己的输入场景下被验证过

你抄的是 sibling 的结构,但结构只覆盖了 sibling 实际跑过的场景。如果你的页面有 sibling 从未触发过的输入边缘(短内容 / 特定设备 / 关闭动画阶段……),抄过来仍然会在那些象限失败。

「sibling 能跑」不等于「sibling 的实现覆盖了所有场景」。

正解

抄之前先建输入维度矩阵,显式对比「sibling 覆盖了哪些象限」和「我的页面需要覆盖哪些象限」,识别出 ⚠️ 行,然后针对每个未覆盖象限单独设计补丁。

常用的输入维度:

| 维度 | 典型变体 | |---|---| | 内容长度 | 短于容器 / 超过容器需滚动 | | 交互方式 | 点击 / 滑动 / 键盘 / 长按 | | 设备平台 | iOS / Android / 模拟器 | | 生命周期阶段 | 打开动画 / 稳定态 / 关闭动画 | | 数据状态 | 首次加载 / 缓存命中 / 空数据 / 错误态 |

具体到这次 bug,矩阵一列出来问题立刻可见:

| 维度 | tag-popup 覆盖 | FAQ 弹窗要覆盖 | 未覆盖象限 | |---|---|---|---| | 内容长度 | 仅长内容(标签总是很多)| 短内容 + 长内容 | ⚠️ 短内容 | | 设备 | iOS + Android | iOS + Android | ✅ | | 关闭动画 | 未单独验证 | 需要 | ⚠️ 关闭动画 |

针对 ⚠️ 行补补丁:

<!-- 1. van-popup + scroll-view(抄 sibling 基线) -->
<van-popup show="{{ show }}" position="bottom" bind:close="onClose">
  <scroll-view scroll-y style="max-height: 55vh;">
    <slot />
  </scroll-view>
</van-popup>
/* 2. page-meta overflow:hidden —— 覆盖短内容穿透象限 */
page-meta {
  overflow: hidden;
}

短内容时 scroll-view 不撑满 popup,手指滑到 padding 区的 touch 会穿透;page-meta overflow:hidden 直接在页面根节点切断穿透,不依赖 scroll-view 是否铺满。

正解:先建矩阵再抄,针对 ⚠️ 象限加补丁
  1. grep 同文件 sibling(同文件 > 同模块 > 跨项目,上下文完全一致的 sibling 最可靠)
  2. 抄之前列出输入维度对比表,标出 sibling 未覆盖的象限
  3. 1:1 抄 sibling 结构作为基线,对每个 ⚠️ 象限单独写补丁
  4. 真机按矩阵笛卡尔积逐格验收,每格录屏 3-5 秒留档

进阶坑:多路 diff 而非单路抄

如果第一轮修复失败了,不要继续「再加一件试试」——每加一件代表你没找到根因,是防御性 over-engineering。

正确姿势是做 3+ 路 diff:同时对比多个 working sibling 和 broken 页面,找出 broken 独有特征。

一个真实案例:某页面锁滚失败,抄了三个 sibling 的四件套仍不 work。误以为缺少 page-meta 就加上去,真机仍然失败。最后 3 路 diff 才发现 broken 页面独有一个 <canvas type="2d" position:absolute(150%)> 深埋在页面子树内,iOS WebKit 把它的 rect 计入了 page content height,导致锁滚失效——而三个 sibling 都没有 native canvas,所以这个特征在单路对比中完全不可见。

「sibling 没做 X 但 work,broken 没做 X 也不 work」
→ 不能推断 X 是缺的那件
→ 恰恰说明 X 不是必需的,broken 独有特征才是真正嫌疑

一句话外卖

抄 sibling 之前先问一句:sibling 的输入场景矩阵,和我的场景矩阵,有没有 sibling 从未触发过的象限?漏问这句,抄得再准也会在边缘场景返工。