scrollIntoView 与 scrollIntoViewIfNeeded API 介绍 以及 解决移动端键盘遮挡

发布于 2022-11-02 12:41:17 字数 10219 浏览 172 评论 0

根据 MDN 的描述,Element.scrollIntoView() 方法让当前的元素滚动到浏览器窗口的可视区域内。

Element.scrollIntoViewIfNeeded() 方法也是用来将不在浏览器窗口的可见区域内的元素滚动到浏览器窗口的可见区域。但如果该元素已经在浏览器窗口的可见区域内,则不会发生滚动。此方法是标准的 Element.scrollIntoView() 方法的专有变体。

因而再有什么回到顶部、去到置顶位置和键盘弹出挡住输入框之类的需求,都可以简单解决了。

然而,面对好用的 API,前端们第一个反映都是,看兼容性!

先看 scrollIntoView 的:

看到一片黄黄绿绿的,基本可以安心,不支持的只是某个属性的取值而已,下面会有介绍~

之后看看 scrollIntoViewIfNeeded

IEFireFox 全红,如果 PC 端想用的话,基本只能内部项目了,略为可惜。但移动端还是绿悠悠的,基本都 OK,可以安心使用~

由于本文是介绍向~ 因而每个属性我都写了点小 demo,点进去就可以体验一下哦!

scrollIntoView

先介绍 scrollIntoView,使用起来其实很简单,获取某个元素后,直接调用 scrollIntoViewIfNeeded() 即可,简单的 demo 点这就好,点一下侧边的小绿块,页面就会滚上去。demo 代码大概长这样:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>scrollIntoView demo1</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      height: 200vh;
    }

    .chunk {
      margin-top: 30vh;
      height: 20vh;
      background: lightcoral;
    }

    .btn {
      padding: 10px 15px;
      position: fixed;
      right: 0;
      top: 50vh;
      background: lightgreen;
      border-radius: 10px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="chunk"></div>
  <div class="btn">click</div>
  <script>
    const btn = document.querySelector('.btn');
    const test = document.querySelector('.chunk');
    btn.addEventListener('click', function() {
      test.scrollIntoView();
    })
  </script>
</body>
</html>

是不是很简单~不过可能有同学就有疑问了,这不就和锚点定位一样吗?感觉毫无意义啊!先别急,当你调用 scrollIntoView 的时候,其实是可以传参数进去的。scrollIntoView 只接受一个参数,但接受两种类型的参数,分别是 Boolean 型参数和 Object 型参数。

先说 Boolean 型参数,顾名思义,参数可以使 true 和 false。如果为 true,元素的顶端将和其所在滚动区的可视区域的顶端对齐。若为 false,元素的底端将和其所在滚动区的可视区域的底端对齐。简单的例子 可以点这里。主要代码如下:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>scrollIntoViewIfNeeded demo</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      height: 200vh;
    }

    .chunk {
      margin-top: 100vh;
      height: 20vh;
      background: lightcoral;
    }

    div[class^=btn] {
      width: 50px;
      padding: 10px 15px;
      position: fixed;
      top: 50vh;
      right: 0;
      border-radius: 10px;
      cursor: pointer;
      text-align: center;
    }

    .btn-top {
      background: lightgreen;
    }

    .btn-bottom {
      margin-top: 50px;
      background: lightblue;
    }
  </style>
</head>
<body>
  <div class="chunk"></div>
  <div class="btn-top">up</div>
  <div class="btn-bottom">down</div>
  <script>
    const up = document.querySelector('.btn-top');
    const down = document.querySelector('.btn-bottom');
    const test = document.querySelector('.chunk');
    up.addEventListener('click', function() {
      test.scrollIntoView(true);
    });
    down.addEventListener('click', function() {
      test.scrollIntoView(false);
    });
  </script>
</body>
</html>

如你所见到的,当传入参数为分别为 true 与 false 时,当点击右侧的按钮时,红色的 div 会贴近可视区域的顶部或底部。

之后是 Object 型参数,这个对象有两个选项,也就是对象里面的 keyblock 与之前的 Boolean 型参数一致,不过值不再是 true 和 false,是更语义化的 start 和 end

另一个选项是 behavior,MDN 上给出三个可取的值,分别是 autoinstant 与 smooth。这个选项决定页面是如何滚动的,实测 auto 与 instant 都是瞬间跳到相应的位置,查阅 W3C 后发现了这么一句:The instant value of scroll-behavior was renamed to auto。因而基本可以确定两者表现是一致的。而 smooth 就是有动画的过程,可惜的是之前提及兼容性时说过,黄色其实不支持某个属性,就是不支持 behavior 取值为 smooth。而且,实测了IE及移动端的UC浏览器后发现,它们根本就不支持 Object 型参数,因而在调用 scrollIntoView({...})时,只有默认的结果,即 scrollIntoView(true)。简单的例子 看这里,如果想体验 smooth 的效果,需要使用 Chrome 或者 Firefox 哦!主要代码如下:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>scrollIntoView demo3</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      height: 200vh;
    }

    .chunk {
      margin-top: 100vh;
      height: 20vh;
      background: lightcoral;
    }

    div[class^=btn] {
      width: 50px;
      padding: 10px 15px;
      position: fixed;
      top: 50vh;
      right: 0;
      border-radius: 10px;
      cursor: pointer;
      text-align: center;
    }

    .btn-top {
      background: lightgreen;
    }

    .btn-bottom {
      margin-top: 50px;
      background: lightblue;
    }
  </style>
</head>
<body>
  <div class="chunk"></div>
  <div class="btn-top">up</div>
  <div class="btn-bottom">down</div>
  <script>
    const up = document.querySelector('.btn-top');
    const down = document.querySelector('.btn-bottom');
    const test = document.querySelector('.chunk');
    up.addEventListener('click', function() {
      test.scrollIntoView({
        block: 'start',
        behavior: 'smooth'
      });
    });
    down.addEventListener('click', function() {
      test.scrollIntoView({
        block: 'end',
        behavior: 'smooth'
      });
    });
  </script>
</body>
</html>

scrollIntoViewIfNeeded

介绍完 scrollIntoView,是时候介绍一下它的变体 scrollIntoViewIfNeeded了。两者主要区别有两个。首先是 scrollIntoViewIfNeeded 是比较懒散的,如果元素在可视区域,那么调用它的时候,页面是不会发生滚动的。其次是 scrollIntoViewIfNeeded 只有 Boolean 型参数,也就是说,都是瞬间滚动,没有动画的可能了。

scrollIntoViewIfNeeded 可以接受一个 Boolean 型参数,和 scrollIntoView 不同,true 为默认值,但不是滚动到顶部,而是让元素在可视区域中居中对齐;false 时元素可能顶部或底部对齐,视乎元素靠哪边更近。简单的例子 可以点这里。大致代码如下:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>scrollIntoView demo1</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      height: 200vh;
    }

    .chunk {
      margin-top: 100vh;
      height: 20vh;
      background: lightcoral;
    }

    div[class^=scrollIntoView] {
      width: 250px;
      padding: 10px 15px;
      position: fixed;
      top: 50vh;
      right: 0;
      border-radius: 10px;
      cursor: pointer;
      text-align: center;
    }

    .scrollIntoView {
      background: lightgreen;
    }

    .scrollIntoViewIfNeeded-top {
      margin-top: 50px;
      background: lightblue;
    }

    .scrollIntoViewIfNeeded-bottom {
      margin-top: 100px;
      background: lightcyan;
    }
  </style>
</head>
<body>
  <div class="chunk"></div>
  <div class="scrollIntoView">scrollIntoView top</div>
  <div class="scrollIntoViewIfNeeded-top">scrollIntoViewIfNeeded top</div>
  <div class="scrollIntoViewIfNeeded-bottom">scrollIntoViewIfNeeded botom</div>
  <script>
    const scrollIntoView = document.querySelector('.scrollIntoView');
    const scrollIntoViewIfNeededTop = document.querySelector('.scrollIntoViewIfNeeded-top');
    const scrollIntoViewIfNeededBottom = document.querySelector('.scrollIntoViewIfNeeded-bottom');
    const test = document.querySelector('.chunk');
    scrollIntoView.addEventListener('click', function() {
      test.scrollIntoView(true);
    });
    scrollIntoViewIfNeededTop.addEventListener('click', function() {
      test.scrollIntoViewIfNeeded(true);
    });
    scrollIntoViewIfNeededBottom.addEventListener('click', function() {
      test.scrollIntoViewIfNeeded(false);
    });
  </script>
</body>
</html>

如文档所说,当红色的 div 完全在可视区域的情况下,调用 scrollIntoView() 是会发生滚动,而调用 scrollIntoViewIfNeeded() 则不会。而我实践后发现了一些文档没有的细节。当元素处于可视区域,但不是全部可见的情况下,调用 scrollIntoViewIfNeeded() 时,无论参数是 true 还是 false,都会发生滚动,而且效果是滚动到元素与可视区域顶部或底部对齐,视乎元素离哪端更近。这个大家需要注意一下~

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

是你

暂无简介

文章
评论
26 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文