【React】如何使用 React Hooks实现一个返回顶部的按钮

最近在把玩React Hooks,感觉用起来是真的流畅,不得不说Hooks刷新了我对于封装组件的体验,趁着手热,赶紧写了一个【回到顶部】的组件来试试水
这篇文章默认各位已经熟悉以下知识点:
React
React Hooks
Typescript(用法很简单,不熟悉其实也能看得懂)
不了解的请先参阅官方文档;

正文

【回到顶部】是许多网页非常常用的按钮,通常放在长页面的右下角,点击可以直接让页面回到顶端。
要实现这个组件,需要以下几个要点:

  • 按钮定位设置为position: fixed;,并且设置位置到屏幕右下角;
.top-jumper {
  position: fixed;
  right: 11%;
  bottom: 15%;
  width: 42px;
  height: 42px;
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 12px;

  &:before {
    content: '▲';
    display: block;
    text-align: center;
    color: #aaa;
    line-height: 42px;
  }
  &:hover:before {
    content: '回顶部';
  }
}
  • 编写最基本的组件结构
import React from 'react';
import './TopJumper.scss'

function TopJumper() {
  return (
    <div className="top-jumper" onClick={()=>window.scrollTo(0, 0)}>
      <span className="text"> </span>
    </div>);
}

export default TopJumper;
  • 当然,一般来说如果页面在顶部,按钮是不显示的,我们需要监听滚动事件,等到页面下拉到一定高度再显示,现在我们结合state hookseffect hooks控制按钮的显隐:
import React, { useEffect, useState } from 'react';
import './TopJumper.scss'

function TopJumper() {
  const [show, switchShow] = useState(false); // 设置状态

  useEffect(()=>{
    const listener = ()=>{
        switchShow(window.scrollY > 300)
    } as EventListener;
    document.addEventListener('scroll', listener);
    return ()=>document.removeEventListener('scroll', listener); // 组件销毁后,取消监听
  }, [show] /* 依赖记得给上,否则死循环 */)

  return show ? (
    <div className="top-jumper" onClick={()=>window.scrollTo(0, 0)}>
      <span className="text"> </span>
    </div>) : null;
}

export default TopJumper;

你以为这就完了?非也。但如果你是“又不是不能用”星人,那么下面的内容对你来说已经没用了!
作为一个资深切图仔,应该察觉到上面那段代码是不完美的,原因就在于浏览器滚动事件调用得太频繁了,会造成一定的性能问题。
我们得实现一个节流函数:

/**
 * create a throttle callback
 * @param callback
 * @param delay
 * @param thisArg
 */
export const createThrottle = (
  callback: Function, 
  delay?: number, 
  thisArg?: unknown
): Function =>{
  let lastInvokeTime: number = Date.now();
  const _delay = Number(delay) || 200
  return (...args: any[]): void=>{
    const now = Date.now()
    if (now - _delay <= lastInvokeTime) {
      return;
    }
    lastInvokeTime = now;
    callback.call(thisArg, ...args)
  }
}

改造我们的listener

const listener = createThrottle(()=>{
  switchShow( window.scrollY > 300 )
}, 500) as EventListener;

最后一步优化:仔细体会一下shouldShow的逻辑,跟上面的有何不同。

const listener = createThrottle(()=>{
  const shouldShow = window.scrollY > 300;
  if (shouldShow !== show) {
    switchShow(shouldShow)
  }
}, 500) as EventListener;

这下才是完全体:

import React, { useEffect, useState } from 'react';
import { createThrottle } from "../assets/helpers";
import './TopJumper.scss'

function TopJumper() {
  const [show, switchShow] = useState(false);
  useEffect(()=>{
    const listener = createThrottle(()=>{
      const shouldShow = window.scrollY > 300;
      if (shouldShow !== show) {
        switchShow(shouldShow)
      }
    }, 500) as EventListener;
    document.addEventListener('scroll', listener);
    return ()=>document.removeEventListener('scroll', listener);
  }, [show])

  return show ? (
    <div className="top-jumper" onClick={()=>window.scrollTo(0, 0)}>
      <span className="text"> </span>
    </div>) : null;
}

export default TopJumper;

写了半天,不给我们看看效果吗?

您好,有的: http://www.kgshino.com

最后的彩蛋:css中对html跟元素添加scroll-behavior: smooth;属性,实现网页平滑滚动(不兼容低版本的浏览器)

html {
  scroll-behavior: smooth;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容