需求还是要听产品经理的——监听滚动的按钮组件实现

391 阅读2分钟

这是我参与更文挑战的第23天,活动详情查看:更文挑战

前言

昨天做的悬浮按钮不尽人意,并不是做的不好,而是不符合需求。程序员要做的就是满足需求的东西。只能是重新来过。

新需求是悬浮按钮在窗口固定的右侧偏上方的位置,当窗口进行滚动的时候按钮隐藏于窗口的右侧,显露一部分,不影响用户查看。如果不滚动则显示按钮,方便用户点击。

需求分析

这个需求主要就是实现两点:

  1. 监听页面滚动
  2. 隐藏以及显示按钮

实现

1.页面监听部分

监听页面滚动,我一开始就想到了window.addEventLinstener的方法,但是由于大部分的移动端布局都不一样,所以真正监听的有可能不是window,又或者是其他的一些组件的滚动。像我们自己的页面window.addEventLinstener就无法监听到列表的滚动。

所以先要找到列表的节点或者父节点进行监听。监听方法一般在节点挂载后绑定,方法大致如下:

componentDidMount() {
    this.scrollDOM.addEventListener("scroll", this.onScroll, {
      passive: false,
    });
}

onScroll = (event) => {
    // 如果没有滚动,设置正在滚动
    if (!this.state.scrolling) {
      this.setState({ scrolling: true });
    }
};

设置了监听方法,当然也要记得取消监听方法:

componentWillUnmount() {
    this.scrollDOM.removeEventListener("scroll", this.onScroll);
}

因为滚动事件是频繁触发的,我们为了保证性能,最好不要一直去更改scrolling的值

所以,我加了一个定时器,和防抖的理念一样,只在1s内未触发时进行赋值。

if (this.timer) {
    clearTimeout(this.timer);
    this.timer = null;
}
this.timer = setTimeout(() => {
    this.setState({ scrolling: false });
    clearTimeout(this.timer);
    this.timer = null;
}, 1000);

2.按钮隐藏显示

这部分相对简单,用css进行控制就可以了。我用的是fixedtransform来更改按钮的位置。

.float-button {
  position: fixed;
  top: 388px;
  right: 0;
  width: 58px;
  height: 58px;
  transition-duration: 0.4s;
}

.float-button.float-button__scrolling {
  transform: translateX(55%);
}

className的赋值用state来判断就可以了。

className = `button float-button ${
    this.state.scrolling ? "float-button__scrolling" : ""
}`;

代码

全部代码如下:

import React, { Component } from "react";

class FloatButton extends Component {
  constructor(props) {
    super(props);

    this.state = {
      scrolling: false,
    };
    this.scrollDOM = window;
    this.timer = null;
  }
  onScroll = (event) => {
    if (!this.state.scrolling) {
      this.setState({ scrolling: true });
    }
    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = null;
    }
    this.timer = setTimeout(() => {
      this.setState({ scrolling: false });
      clearTimeout(this.timer);
      this.timer = null;
    }, 1000);
  };
  componentDidMount() {
    if (this.props.scrollDOM) {
      this.scrollDOM = this.props.scrollDOM;
    }
    this.scrollDOM.addEventListener("scroll", this.onScroll, {
      passive: false,
    });
  }
  componentWillUnmount() {
    this.scrollDOM.removeEventListener("scroll", this.onScroll);
    this.timer = null;
  }
  render() {
    const { img } = this.props;
    return <a {...this.getProps()}>{img && <img src={img} alt="" />}</a>;
  }
  getProps() {
    let props = Object.assign({}, this.props);
    props.className = `button float-button ${
      this.state.scrolling ? "float-button__scrolling" : ""
    }`;
    return props;
  }
}

export default FloatButton;

完整效果如下:

快快快.gif