这是我参与更文挑战的第23天,活动详情查看:更文挑战
前言
昨天做的悬浮按钮不尽人意,并不是做的不好,而是不符合需求。程序员要做的就是满足需求的东西。只能是重新来过。
新需求是悬浮按钮在窗口固定的右侧偏上方的位置,当窗口进行滚动的时候按钮隐藏于窗口的右侧,显露一部分,不影响用户查看。如果不滚动则显示按钮,方便用户点击。
需求分析
这个需求主要就是实现两点:
- 监听页面滚动
- 隐藏以及显示按钮
实现
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进行控制就可以了。我用的是fixed和transform来更改按钮的位置。
.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;
完整效果如下: