Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug Report] scroll-into 返回的currentOption并不准确 #12457

Open
Tamcony opened this issue Nov 20, 2023 · 6 comments · May be fixed by #12621
Open

[Bug Report] scroll-into 返回的currentOption并不准确 #12457

Tamcony opened this issue Nov 20, 2023 · 6 comments · May be fixed by #12621

Comments

@Tamcony
Copy link

Tamcony commented Nov 20, 2023

重现链接

后续补充

Vant 版本

4.6.5

描述一下你遇到的问题。

快速滑动picker的时候,从scroll-into事件获取的currentOption并不是当前选中的那个选项

重现步骤

快速滑动picker

设备/浏览器

No response

Copy link

Hello @Tamcony. Please provide an online reproduction demo by codesandbox or a minimal GitHub repository. Issues marked with need reproduce will be closed if there is no activity within 3 days. For background, please refer to Why reproductions are required.

你好 @Tamcony, 我们需要你提供一个在线的重现示例,以便于我们帮你排查问题。你可以通过点击 codesandbox 创建,或者提供一个最小化的 GitHub 仓库。如果 3 天内未跟进,此 issue 将会被自动关闭。背景请参考 为什么需要最小重现

@Tamcony
Copy link
Author

Tamcony commented Nov 23, 2023

@Tamcony
Copy link
Author

Tamcony commented Nov 23, 2023

一个一个滑动的话,currentOption是当前选中的值。
通过惯性滚动的话,currentOption并不是当前选中的值。

@inottn
Copy link
Collaborator

inottn commented Nov 23, 2023

现在的实现是只在触摸时触发 scroll-into 事件,所以惯性滚动时不会触发。
不过看了下当初引入这个功能的相关 pr 和 issue,从动机上看在惯性滚动时应该也是要触发的。

@Tamcony
Copy link
Author

Tamcony commented Nov 23, 2023

现在的实现是只在触摸时触发 scroll-into 事件,所以惯性滚动时不会触发。 不过看了下当初引入这个功能的相关 pr 和 issue,从动机上看在惯性滚动时应该也是要触发的。

是的,我有一个需求是滚动分页加载,我开始想用这个事件处理,然后和我预想的并不一样,那这种情况是只能用onChange吗?因为我看也没有reachBottom相关的事件,只能自行判断index了。

@nemo-shen
Copy link
Contributor

nemo-shen commented Jan 30, 2024

看了下原本的issue: #11754
很有趣,原本是想实现 ios picker惯性滚动时候的咔哒声

但是根据PR: #11757 的实现方式,我们是做不到惯性滚动的时候获取每个item进入中间视窗的逻辑的。
事实上 JavaScript 除非是 监听对象的 scroll 才可以监听每次的滚动偏移量。
但是不幸的是,我们的 Picker 组件实现滚动效果,实际上用的是 transform 这个css做动画效果。
不使用 overflow-y: scroll 的原因是因为我们最后一定要准确让某个 Item 能到达中间视窗,而不是任意状态的滚动。
这样一来,我们就连 scroll 这个事件都没法捕捉了。

有一个解法是:模拟惯性滚动时Item到达视窗的逻辑
目前我们的 PickerColumn 中已经通过 touchstarttouchend 计算出了最终要滚动到的Y轴偏移量,
因此,我们可以根据 startOffset(即初始静止状态偏移量) 和 endOffset(即惯性滚动后最终的偏移量),
计算出我们需要经过的偏移量,再根据 transitionDuration(即动画播放时长) 大概计算出每次Item到达中间视窗的时机,模拟触发 onScrollInto

以下是伪代码:假设触摸方向是从下到上

const startOffset = 0;           // 初始偏移量 '0px'
const endOffset = -500;          // 触摸后知道的需要到达的偏移量 '-500px'
const itemHeight = 40;           // 每个Item高度为 '40px'
const transitionDuration = 1000; // 动画效果时长,假设 '1000ms'

// 算出我们需要经过的总偏移量
const totalOffset = Math.max(startOffset, endOffset) - Math.min(startOffset, endOffset);

// 根据总偏移量和每个item高度,计算出总计需要经过的item数量
const itemCount = Math.floor(totalOffset / itemHeight);

// 根据 动画时长 和 需要经过的item数量,计算出每次触发 scrollInto 的间隔时间
const time = transitionDuration / itemCount;

// 最终:当动画开始时执行
const timer = setInterval(() => {
  emit('onScrollInto');
}, time)

// 这里需要移除定时器
const clearTimer = setTimeout(() => {
  clearTimeout(clearTimer);
  clearInterval(timer);
},transitionDuration);

关键问题是要尽可能保证每次 scrollInto 在视觉上是正确的。
另外快慢触摸会导致动画的快慢如何保证效果一致性也是要考虑的一个问题,比如说用户一下子滑动了偏移1000px,或者用户只稍微触摸了一下滑动了100px,由快到慢的动画效果和 scrollInto 如何对应也需要考虑才可以。


如果有其他idea,欢迎讨论:)

@nemo-shen nemo-shen linked a pull request Feb 4, 2024 that will close this issue
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants