封面

简介

回到页面顶部、兼容性、最佳写法、滚动到任意处

大家一起被捕吧 中刚写了:

在日常开发中我们往往会从用户那获得各种输入,例如搜索框、评论框、文章内容等等。

结果在 segmentfault 阅读评论时看到了一个链接一点直接把我给滚动到顶部,顿时心中一阵 惨叫双手捶胸 后把页面拉回评论并打开了 控制台 查看了链接为何方神圣:

<a href="#">...</a>

顿时又是一阵 惨叫双手捶胸 原来 segmentfault 评论是支持 markdown 语法的,如果再评论里输入 [...](#) 则会被转换成如上代码。

好奇心突发跑到了 掘金 测试了一下带连接的评论,打开 控制台 看了看由于使用了 target="_blank" 没有出现被传送到顶部的情况,心里暗暗道 喵哉 🐱 以后还是得小心行事,碰巧每日30秒正愁不知道写什么那就来写写 回到顶部 吧。

回到顶部

第一种写法就介绍一下今天被中全套的代码,利用了 锚点 来实现回到顶部:

<a href="#"回顶部></a>

如果需要滚动到别的元素可以使用 id 属性配合 锚点 来实现:

<header id="header">我是头部</header>
<a href="#header">回到页面头部</a>

不过由于这种方法 滚动 得太快了,性能肯定是很好就是体验不怎么好。不过我们可以使用 css 的 scroll-behavior 属性来提升体验:

html, body {
  scroll-behavior: smooth;
}

虽然第一种方法配合 css 的 scroll-behavior 属性显得挺不错,但是 scroll-behavior 兼容性挺不高的具体可以看 caniuse

迴到顶部

由于在页面垂直滚动过程中会改变 window.scrollY 的值,第二种便是写法利用 window.scrollTo() 把它设置为 0 来实现回到顶部:

window.scrollTo(0, 0)

不过这样使用也会导致 滚动 得太快带来的体验不好,这个时候我们可以利用 window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画,该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。

这里使用里一个来判断当页面没有滚动到顶部时循环调用 window.requestAnimationFrame 来进行逐步滚动,每次滚动的距离 c - c / 8 随着 c 的减小而减小进而实现滚动效果:

const scrollToTop = () => {
  const c = document.documentElement.scrollTop || document.body.scrollTop;
  if (c > 0) {
    window.requestAnimationFrame(scrollToTop);
    window.scrollTo(0, c - c / 8);
  }
};

不过继续查阅 caniuse 中的 window.requestAnimationFrame() 在主流浏览器中支持挺好的,但是需要兼容 ie6-9 的同学就得另外寻找方法了。仔细想想 window.requestAnimationFrame()setTimeout() 好像有点相似。

window.requestAnimationFrame 回调函数执行次数通常是每秒60次即一秒60帧,将 setTimeout 执行的频率也设置为一样的就行了:

if (!window.requestAnimationFrame) {
    window.requestAnimationFrame = function (callback) {
        return setTimeout(callback, 1000 / 60);
    }
}

const scrollToTop = () => {
  const c = document.documentElement.scrollTop || document.body.scrollTop;
  if (c > 0) {
    window.requestAnimationFrame(scrollToTop);
    window.scrollTo(0, c - c / 8);
  }
};

搞定神器 ie6-9 的兼容问题。

囬到顶部

第三种写法使用函数 Element.scrollIntoView() 可以将选中的元素移动到 可视区域可视区域 更多相关知识点可以看之前的一篇文章 巧用可视区域

document.querySelector('body')
    .scrollIntoView({
        behavior: 'smooth',
        block: 'start',
    })

代码实现比起第三种简单了不少,当 css 的 scroll-behavior 被设置时会默认设置 Element.scrollIntoView()behavior,依旧打开 caniuse 查看兼容性会发现和 window.requestAnimationFrame() 比起来差不了多少,在神器 ie6-9 也有兼容问题。

囘到顶部

第四种方法将前面方法进行一个整合,页面支持 Element.scrollIntoView() 则直接使用第三种方法,如果页面不支持则使用第二种方法。对于 Element.scrollIntoView() 的支持利用到了 window.getComputedStyle() 也有兼容性问题需要判断一下:

let scrollToTop;

if (window.getComputedStyle && window.getComputedStyle(document.body).scrollBehavior) {
    scrollToTop = () => document.querySelector('body')
        .scrollIntoView({
            behavior: 'smooth',
            block: 'start',
        });
} else {
    if (!window.requestAnimationFrame) {
        window.requestAnimationFrame = function (callback) {
            return setTimeout(callback, 1000 / 60);
        }
    }

    scrollToTop = () => {
        const c = document.documentElement.scrollTop || document.body.scrollTop;
        if (c > 0) {
            window.requestAnimationFrame(scrollToTop);
            window.scrollTo(0, c - c / 8);
        }
    };
}

在开发中要注意浏览器的兼容性,多使用 caniuse 来帮助我们参看兼容性情况。并根据产品的开发需求来书写代码,例如不需要兼容 ie6-9 时我们可以直接使用 Element.scrollIntoView()。在刚才的学习中除了学习了回到顶部外,只需再学习一下获取元素所在 y 轴坐标或者高度就会 一不小心顺手 学习了滚动到页面各处。

一起成长

在困惑的城市里总少不了并肩同行的 伙伴 让我们一起成长。

  • 如果您想让更多人看到文章可以点个 点赞
  • 如果您想激励小二可以到 Github 给个 小星星
  • 如果您想与小二更多交流添加微信 m353839115

微信公众号

本文原稿来自 PushMeTop


书籍推荐