接到需求要做一个类似 APP 通信录的带有快速索引的界面,找了找现成的库就找到了 Ant Design Mobile 里面的 IndexdList 最接近我的预期。下面记录一下我调试 IndexdList 的辛路历程。
注:想看解决方法的童鞋可以直接从步骤 17 开始看。
开发历程
下面是我开发的具体步骤,其中走了很多弯路,做了一些蠢事,幸好弯弯绕绕最后终于解决了。
- 复制官方 demo 到本地跑。
- 发现 demo 不可行 —— IndexList 是显示出来了,但是索引按钮点击后不滑动到对应位置。第一反应是怀疑列表数据源 DataSource 内容不一样,想打印出来对比下。
- 于是 clone 官方代码,想看下运行代码的 demo 看看其具体实现。
- 但是!在项目中只找到了组件源码和demo文档,没有demo源码
- 由于 ant design mobile 中很多东西都是外部 import 子库,我就认为 demo 代码是不是外部引入的。疯狂的找 ant design mobile 中 ListView 的 demo 源码。
- 找着找着突然反应过来 antd 是用的 Bisheng 来做的 markdown 转 html 静态页面。
- 找到了 demo 了,开始进行验证对比官方代码和我的代码,发现我本地和官方的 DataSource 是一样的。
- 迷茫中……
- 心烦意乱,想放弃自己写个。但是总觉得不合适,更倔强的想解决这个奇怪的问题。
- 想用 rmc-list-view 来做(antd 的 list-view 就是对 rmc-list-view 的封装)。
- 结果不行,想想发现其实两者就是一个东西。
- 最后决定还是相信 antd,不相信自己撸,不走歪门邪道。
- 突然想到彪哥之前一直去 node_module 中解决问题,我就跑到 node_module 中给 listview 组件部分打上 log,逐步找到 IndexdList 滑动的原理。
- 追踪到最后发现就是一个滑动的简单逻辑。
if (_this4.props.useBodyScroll) {
setDocumentScrollTop(sec.getBoundingClientRect().top - lv.getBoundingClientRect().top + getOffsetTop(lv));
} else {
lv.scrollTop += sec.getBoundingClientRect().top - lv.getBoundingClientRect().top;
}
function setDocumentScrollTop(val) {
window.document.body.scrollTop = val; // chrome61 is invalid
window.document.documentElement.scrollTop = val;
}
- 代码超级简单吧。就是 body 或者 element 的 scrollTop 属性来控制滑动(想想其实也没有其他更合适的方法了)。
- 由于我使用了 useBodyScroll 去滑动 body,但是我的 body 高度写死了
100%
。即虽然我的列表有5000 px
,但是我的 body 只有100vh
,所以必然不会滑动。 - 去除 useBodyScroll,使用元素的 scrollTop 属性。看到官方文档里有一句需要手动设置高度。就先随便设了个 1000px。点击索引列表按钮滑动,可行。
- 知道了底层逻辑,之后的事情就简单了。调试 CSS 到预期样式就好。具体可以参照 Element.scrollTop | MDN 文档。
- 避免出现双重滚动条,否则索引值的滑动会很奇怪。
经验教训
虽然这么一个简单的东西却花了我一天多的时间来完成,但是也学到了不少经验教训。
- 不要快速怀疑久经沙场的技术,却相信自己可以撸一个更好的。
- 技术文档一定要认真仔细的看完再开工,我这次就吃了这么个亏。
- 不用什么问题都去找源码中找起,太费时间。可以先看看文档、查查 Google。
- 学到了一种非常实用的调试方法:遇到引用的外部库有问题,可以去 node_module 中给源码打 log 来调试。(注意修改 node_module 后可能需要重新执行 npm start 编译打包。)
- 源码的 example 不一定是项目,也可以是 markdown 转静态页面。
最后一个教训是:多难为难为自己,虽然过程很不舒服,但是结果往往能从中学到不少东西。