likes
comments
collection
share

H5 列表 flex布局横向滚动+弹性左滑松手查看更多关于H5如何实现“列表弹性左滑松手查看更多”的事,我没有找到轮子,

作者站长头像
站长
· 阅读数 190

1. 引言

💁‍♀️👉 什么是“弹性左滑松手查看更多”? H5 列表 flex布局横向滚动+弹性左滑松手查看更多关于H5如何实现“列表弹性左滑松手查看更多”的事,我没有找到轮子, 如图⬆️,在横向滑动的列表末端加一个指示滑块,列表滑动到尽头时滑块弹性拉伸,拉伸到一定程度松手可触发事件~效果就像这样↙️↙️ H5 列表 flex布局横向滚动+弹性左滑松手查看更多关于H5如何实现“列表弹性左滑松手查看更多”的事,我没有找到轮子, 这个交互在App上算是比较常见了,搜一搜有很多代码可以参照。 而当我拿到这个需求,要在h5中实现时,想找找参考,别说插件了,连代码块都没搜到 ~ 🤦🏻‍♀️ 或许搜索姿势不对?anyway,找不到轮子只能自己写一写了。

2.方案

2.1 思考

看到这种弹性滑动首先想到的是swiper是否可以实现,翻了翻演示案例,嗯,没有。参考swiper利用translate变换写一个虚拟滚动呢?还要搞平滑滚动动画,想了想略复杂。是不是可以在原生滚动的基础上加上触底拉伸的效果呢?

2.2 flex布局横向滚动

首先利用flex布局实现卡片列表横向滚动。我们在列表的最后,插入一个“查看更多”的卡片。flex布局下,“查看更多”会与列表的其他卡片自动对齐高度,这是使用弹性盒子的好处。

.list{
    display: flex;
    flex-wrap: nowrap; /* 弹性盒子不折行 */
    overflow-x: auto;
}
.item{
    /* 内部卡片样式 ... */
}
.item-more{
    content: "查看更多";
    writing-mode: vertical-lr; /* 竖排文字 */
    /* ... */
}

2.3 藏在列表右侧的色块

现在列表搞定,如何实现拖拽拉伸?我的思路是在列表右侧定位一个元素,隐藏在屏幕之外,当列表滚动到最右,继续左滑时,整个列表进行translate左移,拉出隐藏元素。

H5 列表 flex布局横向滚动+弹性左滑松手查看更多关于H5如何实现“列表弹性左滑松手查看更多”的事,我没有找到轮子,

具体做法: 监听列表touch事件。判断当列表滚动距离已到达最大,开始实时记录触摸位置pageX,通过计算手指移动距离,改变列表容器的translateX,实现位移变换。当touchend,判断位移达到指定距离,可以触发“松手”事件。

本文中代码仅为示例代码,变量声明、语法逻辑等做了一些简化,理解其意思即可


.list{
    /* ...flex */
    position: relative;
    transition: all 0.1s; /* 使位移平滑过渡 */
}
.after{
    position: absolute;
    width: 100%;
    right: -100%;
    top: 0;
    height: 100%;
    background: #f5f5f5; /* 与“查看更多”同色 */
}

H5 列表 flex布局横向滚动+弹性左滑松手查看更多关于H5如何实现“列表弹性左滑松手查看更多”的事,我没有找到轮子, H5 列表 flex布局横向滚动+弹性左滑松手查看更多关于H5如何实现“列表弹性左滑松手查看更多”的事,我没有找到轮子, 效果如下: H5 列表 flex布局横向滚动+弹性左滑松手查看更多关于H5如何实现“列表弹性左滑松手查看更多”的事,我没有找到轮子,

2.4 弹性拉伸

实现到这里已经完成了基本功能:左滑到底拉伸,松手触发事件。在以上的代码中,手指移动和列表的位移是一比一设置,而这个拉动体验很差,接下来考虑交互优化,做一个弹性的拉伸效果,即:随着手指滑动,拉动越来越慢直到锁死

具体做法是修改上面 transdragDistance 的函数对应关系。这里就要用到数学公式了。

fooplot 在线方程 H5 列表 flex布局横向滚动+弹性左滑松手查看更多关于H5如何实现“列表弹性左滑松手查看更多”的事,我没有找到轮子,

如上,在fooplot网站生成了一个抛物线方程,一个顶点式:在 0<x<100 的范围内,随x增加,y增加得越来越缓慢。(函数中的62、100分别对应列表滑动和手指滑动的最大距离,数值可以根据实际需要调整)

对应代码:

const DISTANCE_MAX = 100; // 手指移动的最大距离

// 在上图代码18行前插入计算
trans = DRAG_MAX - (DISTANCE_MAX / DRAG_MAX ** 2) * (trans - DRAG_MAX) ** 2;

看下最终效果✅

H5 列表 flex布局横向滚动+弹性左滑松手查看更多关于H5如何实现“列表弹性左滑松手查看更多”的事,我没有找到轮子,

3. 始料未及之坑

花了3小时完成了功能,长出一口气,

H5 列表 flex布局横向滚动+弹性左滑松手查看更多关于H5如何实现“列表弹性左滑松手查看更多”的事,我没有找到轮子,

没想到交付给测试同学,马上就喜提bug。

3.1 坑之iPhone兼容

“😏 你这在iPhone上有bug,露白了”。

???,一直用的安卓机,没想到在iPhone中,滚动列表是自带拉伸回弹效果的

🤷🏻‍♀️ 在安卓和电脑浏览器模拟器中,列表左滑到最右端时,就无法继续拖动了,而iPhone中,还可以继续拉拉拉,导致“查看更多” 和 .after 元素之间,出现一段断层间隙,露出了列表的底色。(因为没有机器不太方便录图,自行理解)

那么iPhone自带的滚动拉伸有什么特点呢?调试发现当列表拉伸时,上面代码中的 scrollDistance值出现10、20、30、100...ok, 原来iPhone中,可滚动元素的 offsetWidth + scrollLeft 是可以大于 scrollWidth 的!😳惭愧,开发这么多年,才知道这件事...

那么这样就好办了,在iPhone中就不要再判断位移了,直接在列表底层定位一个背景色元素,使用系统自带的列表回弹,通过露出这个底色元素实现“查看更多”的拉伸效果,而不触发列表形变赋值。

代码修改之后:

// 原图代码11行
if(scrollDistance>0){
    trans = 0;
    draggingOk = scrollDistance>DRAG_LINE; // 直接用滚动条偏移量判断是否可触发事件
} else if(scrollDistance===0){
    // 不变
} else {
    // 不变
}

3.2 坑之继续安卓兼容

一顿修改猛如虎,提交之后。。。

“🥺 其中一个安卓测试机,滑到最右后,怎么拖不动了?!”。

迎来了新的bug。。。

H5 列表 flex布局横向滚动+弹性左滑松手查看更多关于H5如何实现“列表弹性左滑松手查看更多”的事,我没有找到轮子,

拿来了该测试机一番核验之后,原来,安卓机的scrollDistance 也是可以大于0的, 代码走到了错误的路径,导致没有触发trans变化。又get到了新的知识。。。

调试发现,该测试机的滚动条溢出值为0.6666666px,并且后来在测试其他机器的时候,出现了-0.3333333px这样的值,溢出在1px以内,最终修改代码为:

if(scrollDistance>1){
    // ...
} else if(scrollDistance>-1){
    // ...
} else {
    // ...
}

get 到这个问题后要注意,以后若是写触底加载之类的功能时,判断触底状态,不可直接用 offsetWidth + scrollLeft - scrollWidth === 0 判断

4. 代码共享

我把组件拆出来做了一个插件,为提高可用性做了一些配置项。一些案例效果:

H5 列表 flex布局横向滚动+弹性左滑松手查看更多关于H5如何实现“列表弹性左滑松手查看更多”的事,我没有找到轮子,

👉点击查看 Github 地址

代码是React+Typescript写的,需要的可以直接引用,不适合的可以做参考自己写一份啦,代码并不十分复杂。

5. 写在最后

整个实现过程还是比较粗糙,还有很多可优化的地方,欢迎提出宝贵意见~

以及有其他方案的话欢迎交流~

转载自:https://juejin.cn/post/7028149988882382856
评论
请登录