背景:一次看起来简单的 UI 改造
画点AR绘画手帐是一个 Taro 4 + Vue3 的微信小程序,渲染器用的是 Skyline。它本质是个"线稿库 + 描边"的工具,首页按分类展示线稿素材。分类一多,最初的换行平铺就显得拥挤,于是我把分类条改成单行横滑,用 scroll-x 的 scroll-view 承载。
改动上线后用户反馈:横着滚到后面,点某个分类,横条会"啪"地弹回第一个。一个再普通不过的交互,卡了我三轮。
第一轮:错怪了 scroll-into-view
我第一反应是 scroll-into-view 没生效。毕竟这个小程序页面回顶的按钮一直靠它工作得好好的,直觉上横滚只是换个方向。
但实测 Skyline 的横滚 scroll-view 上 scroll-into-view 就是不灵。根子有两处:一是 v-for 出来的 chip 被包在 Fragment 里,id 选择器在 Skyline 渲染器下查不到;二是 scroll-into-view 是常驻生效属性,只要后续任意一次 setData 触发,它就会把滚动位置拽回那个 chip。换句话说,横滚场景里它不但没用,还会持续制造回弹。结论很直接:横滚别碰 scroll-into-view,得换受控方案。
第二轮:受控 scroll-left 仍然回弹
改成受控方案:用 Taro.createSelectorQuery() 量出 .cat-bar 的 boundingClientRect + scrollOffset,以及所有 .cat-chip 的 boundingClientRect(selectAll + 下标,不用 #id),算出目标偏移 chips[idx].left - bar.left + cur,两侧留 22px、已可见就不滚,写回 catScrollLeft,并给 .cat-bar 绑 :scroll-left 和 @scroll。
为确认不是"没编译进去",我用 Python 解析 dist/pages/index/index.js,看到 scroll-left 绑定、selectAll 量位置、400ms 清空逻辑都在产物里。方案本身没问题,可用户点选后还是回弹。
真根因:Skyline 只在值变化时应用滚动
第三轮才看清真正的语义。Skyline 的 scroll-view 只在 scroll-left 绑定值"发生变化"的那次渲染才应用滚动。而我点分类后 loadFirstPage() 会把横条位置重置为 0,重算出的目标偏移恰好等于当前绑定值(比如都是 300),Vue 判定无变化、不触发更新,条子就停在最左边——视觉上就是"滚过去又弹回"。
这里还有两个配套陷阱:@scroll 里若直接 setData 会打断原生滚动,必须只记录真实位置,停下 220ms 才回写;loadFirstPage 的位置重置是异步的,如果补定位在同一拍量坐标,量到的是重置前的旧值,会算出"不用滚"。
工程方案
最终落地的修法:
- 写入
catScrollLeft统一走applyCatScroll(),每次交替加0/1px 偏移,强制让值变化。1px 在 335px 可视区里完全看不出来,但必须用整数——亚像素偏移会被渲染器取整丢掉。 @scroll内只记真实位置、不 setData,停下 220ms 才把真实位置同步回绑定值,避免之后任何 setData 把条子拉回旧位置。loadFirstPage()结尾的补定位延一拍(setTimeout60ms)再量,避开异步重置的窗口。
用户确认这次生效了。
同天的另一个静默失效:渐变
同一天还有一处背景光晕没渲染。Skyline 下 radial-gradient 只支持 circle、尺寸只支持 px、background-image 最多 2 个值。而 Taro 的 pxtransform 会把 px 编译成 rpx,等于"渐变尺寸只能写 px"这条在 Taro 里没法落地。解法是索性不写渐变尺寸,用默认的 farthest-corner,范围交给节点自身的 width/height(布局用 rpx 没问题)。
为了不让这类坑再复发,我写了个编译期断言脚本:断言前先去掉 CSS 注释(避免把注释里的反面示例当真样式),再检查每条 background-image 里 gradient( 数量不超过 2、radial-gradient 头部不出现两个长度(椭圆)也不带 rpx。9 个 scss 块编译通过、零 warning、无渐变违规。
方法论沉淀
这一天的两次排查,沉淀出几条对 Skyline 开发通用的纪律:
- 样式静默失效多,改样式前先过官方限制清单,别靠猜。
- "改了没效果"先确认编译产物时间戳晚于源文件,再用解析器验证绑定真的进了产物,而不是反复试。
- 横滚 scroll-view 的
scroll-into-view不生效,统一用受控scroll-left+ 交替偏移强制重应用。 - 设计 token 收敛到
tokens.scss一个文件,换主题只改一处;共享文件用//行注释,避免被@use复制到每个页面。
后来我把这套 Skyline 样式限制与断言固化为一个"微信小程序 Skyline 样式守卫"的小技能,发到了 SkillHub,给同样在被 Skyline 静默失效折磨的同学复用。