Skip to content

scrollIntoView引发的思考 #9

@zhaoqize

Description

@zhaoqize

起因

同事最近在开发h5页面的时候,遇到了点击输入框,而 输入框输入法 遮挡的问题。

这个问题只会只在 安卓手机 中出现。

想法

一出现这种问题,第一感觉就是认为页面的高度被改变压缩了。
首先想到的是用万能JavaScript去动态改变滚动高度(首先想到的是这两个方法scrollBy和scrollTo
搜索之后发现有这么两个东西

  • scrollIntoView

方法让当前的元素滚动到浏览器窗口的可视区域内

  • scrollIntoViewIfNeeded

是 Element.scrollIntoView() 的变体,如果该元素已经在浏览器窗口的可见区域内,则不会发生滚动

解决方案

@Tao-Quixote 这个大兄弟已经说的很清楚了,具体见scrollIntoViewIfNeeded 与 scrollIntoView

下面摘录一部分:

根据MDN文档,Element.scrollIntoView是一个实验性质的方法,提示截图如下:

Element.scrollIntoViewIfNeeded是一个非标准的特性,建议不要在生产环境中使用,提示截图如下:

其实这两个特性,我个人感觉应用最多的场景应该是在移动端,当表单元素获得焦点的时候滚动到视野中,避免软键盘遮挡元素。鉴于Element.scrollIntoView无论设置什么参数,且不论是否在视野中都会滚动的特点,Element.scrollIntoViewIfNeeded特性应该比Element.scrollIntoView体验好。

虽然MDN文档中说Element.scrollIntoViewIfNeeded是非标准特性,但是在移动端的支持还是非常好的,以下截图来自caniuse:

但是反观Element.scrollIntoView这个实验特性,在移动端的支持并不是特别好,以下截图来自caniuse:

根据上面的比较应该可以得出结论:在移动避免软键盘遮挡表单元素时,应该使用Element.scrollIntoViewIfNeeded特性来实现元素滚动到视野中,不论是体验还是浏览器支持,该特性都好于Element.scrollIntoView特性。

scrollIntoViewIfNeeded不起作用

你以为这就完了?想法太美好!
在实际的使用中,发现scrollIntoViewIfNeeded有时候会不起作用!
这里需要注意一点:就是focus事件和键盘弹起是有交互时间的。
执行scrollIntoViewscrollIntoViewIfNeeded的时机应该是在键盘弹出之后。

// 伪代码
setTimeout(() => {
    element.scrollIntoView()
}, 400);

scrollBy和scrollTo区别

  • scrollBy() 方法可把内容滚动指定的像素数。
  • scrollTo() 方法可把内容滚动到指定的坐标。
    含义的描述很明显就能看出区别了,一个在现有基础上的增/减量,是一种相对的概念。另外一个是绝对量。

滚动的平滑度问题

无论是scrollBy还是scrollTo,他们到达制定的位置都非常生硬(瞬达),没有过渡的效果。
smoothscroll 这个库就很好的处理了这种情况。
具体的效果看这里:smoothscroll演示

当然作为一个非常好奇的人,就很想看看它是怎么在400多行代码中实现的这个效果,因为以前来说这种效果会用setTimeout这种方法来实现,虽然效率不是很好,但是最起码能实现这种功能。
这里我们能找到它使用requestAnimationFrame方法实现的。

参考:

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions