js、react、vue里滚动到底部加载数据和滚动到顶部实现(js监听滚动事件,到底部请求接口)
前言:
最近在做一个项目,一个列表展示原本是分页器,点击下一页,请求接口。但是业务说需要改成滑倒底部,加载数据。
一、实现过程
整体思路就是 获取 滚动元素的 scrollHeight(元素内容的总高度)、clientHeight(元素的可见高度)、scrollTop(元素滚动条垂直滚动的距离)
- scrollHeight表示元素内容的总高度,包括溢出部分;
- clientHeight表示元素的可见高度,不包括滚动条、边框和外边距;
- scrollTop表示元素滚动条垂直滚动的距离,即内容顶部相对于可见区域顶部的偏移量。
然后 在滚动事件里 判断 满足scrollTop+clientHeight >=scrollHeight 即可调用接口。
1.html+js
Document
2.react实现
import React, { Component } from 'react';class Index extends Component {constructor(props) {super(props)this.state = {data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}}componentDidMount() {window.addEventListener("scroll", this.add);//监听滚动事件}add = () => {let { data, page } = this.state;console.log(Math.round(this.getScrollTop() + this.getWindowHeight()), this.getScrollHeight())if (Math.round(this.getScrollTop() + this.getWindowHeight()) >= this.getScrollHeight() - 1) {//项目中在这里面请求接口data.push(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);this.setState({data})}}//获取滚动条被卷进去的高getScrollTop = () => {var scrollTop = 0, bodyScrollTop = 0, documentScrollTop = 0;if (document.body) {bodyScrollTop = document.body.scrollTop;}if (document.documentElement) {//兼容iedocumentScrollTop = document.documentElement.scrollTop;}scrollTop = (bodyScrollTop - documentScrollTop > 0) ? bodyScrollTop : documentScrollTop;return scrollTop;}//获取可滚动高度getScrollHeight = () => {var scrollHeight = 0, bodyScrollHeight = 0, documentScrollHeight = 0;if (document.body) {bodyScrollHeight = document.body.scrollHeight;}if (document.documentElement) {//兼容iedocumentScrollHeight = document.documentElement.scrollHeight;}scrollHeight = (bodyScrollHeight - documentScrollHeight > 0) ? bodyScrollHeight : documentScrollHeight;return scrollHeight;}//获取可见区域高getWindowHeight = () => {var windowHeight = 0;if (document.compatMode == "CSS1Compat") {//兼容iewindowHeight = document.documentElement.clientHeight;} else {windowHeight = document.body.clientHeight;}return windowHeight;}componentWillUnmount(){window.removeEventListener("scroll",this.add);//销毁监听事件防止内存泄漏}render() {let { data } = this.state;return ({data.map((item, index) => {return (- { height: "200px" }} key={index}>{item}
)})}
);}
}export default Index
3.react升级版本
为什么升级呢,因为 我发现上一个版本不适合所有场景(基于body的)。上面的版本知识和 没有指定 滚动dom的情况。而大部分使用场景都是需要指定某个元素的。所以我做了改动,也就是这个版本更灵活。
1.class版本
import React, { FC, useEffect, useRef, useState, Component } from 'react'
import styles from './Home.module.less'
class Home1 extends Component {constructor(props) {super(props)this.state = {data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],dom: null}}componentDidMount() {let dom = document.getElementById("list-box");dom.addEventListener("scroll", this.add);//监听滚动事件this.setState({dom})}add = () => {let { data, page } = this.state;console.log(Math.round(this.getScrollTop() + this.getClientHeight()), this.getScrollHeight())if (Math.round(this.getScrollTop() + this.getClientHeight()) >= this.getScrollHeight() - 1) {//项目中在这里面请求接口let arr=[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];let data1 = data.concat(arr);this.setState({data: data1})}}//获取滚动条被卷进去的高getScrollTop = () => {const { dom } = this.state;let scrollTop = 0;if (typeof dom.scrollTop !== "undefined") {// 如果浏览器支持直接获取scrollTop属性scrollTop = dom.scrollTop;} else if (typeof dom.pageYOffset !== "undefined") {// 如果浏览器支持pageYOffset属性scrollTop = dom.pageYOffset;} else if (typeof dom.scrollY !== "undefined") {// 如果浏览器支持scrollY属性scrollTop = dom.scrollY;} else if (typeof document.documentElement.scrollTop !== "undefined") {// 兼容IE浏览器的获取scrollTop属性scrollTop = document.documentElement.scrollTop;} else if (typeof document.body.scrollTop !== "undefined") {// 兼容IE浏览器的获取scrollTop属性scrollTop = document.body.scrollTop;}return scrollTop;}//获取可滚动高度getScrollHeight = () => {const { dom } = this.state;var scrollHeight = 0;if (typeof dom.scrollHeight !== "undefined") {// 如果浏览器支持直接获取scrollHeight属性scrollHeight = dom.scrollHeight;} else if (typeof dom.offsetHeight !== "undefined") {// 如果浏览器支持offsetHeight属性scrollHeight = dom.offsetHeight;} else if (typeof dom.clientHeight !== "undefined") {// 如果浏览器支持clientHeight属性scrollHeight = dom.clientHeight;}return scrollHeight;}//获取可见区域高getClientHeight = () => {const { dom } = this.state;var clientHeight = 0;if (typeof dom.clientHeight !== "undefined") {// 如果浏览器支持直接获取clientHeight属性clientHeight = dom.clientHeight;} else if (typeof dom.offsetHeight !== "undefined") {// 如果浏览器支持offsetHeight属性clientHeight = dom.offsetHeight;}return clientHeight;}componentWillUnmount() {const { dom } = this.state;dom.removeEventListener("scroll", this.add);//销毁监听事件防止内存泄漏}render() {let { data } = this.state;return ({data.map((item, index) => {return (- {item}
)})}
);}
}export default Home1;
样式:
* {margin: 0;padding: 0;
}.listBox {width: 300px;height: 800px;border: 1px solid red;overflow: auto;}.listItem {width: 100%;height: 80px;border-bottom: 1px solid blue;
}
2.hook版本
import React, { FC, useEffect, useRef, useState, Component } from 'react'
import styles from './Home.module.less'
const Home1 = () => {const [data, setData] = useState([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);useEffect(() => {let dom = document.getElementById("list-box");dom.addEventListener("scroll", add);//监听滚动事件return () => {// 组件卸载时,移除滚动事件监听器dom.removeEventListener('scroll', add);};}, [])const add = () => {//console.log(Math.round(getScrollTop() + getClientHeight()), getScrollHeight())if (Math.round(getScrollTop() + getClientHeight()) >= getScrollHeight()-1) {//项目中在这里面请求接口let data1 = data.push(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);setData(prevData => prevData.concat(data1));}}//获取滚动条被卷进去的高const getScrollTop = () => {let dom = document.getElementById("list-box");let scrollTop = 0;if (typeof dom.scrollTop !== "undefined") {// 如果浏览器支持直接获取scrollTop属性scrollTop = dom.scrollTop;} else if (typeof dom.pageYOffset !== "undefined") {// 如果浏览器支持pageYOffset属性scrollTop = dom.pageYOffset;} else if (typeof dom.scrollY !== "undefined") {// 如果浏览器支持scrollY属性scrollTop = dom.scrollY;} else if (typeof document.documentElement.scrollTop !== "undefined") {// 兼容IE浏览器的获取scrollTop属性scrollTop = document.documentElement.scrollTop;} else if (typeof document.body.scrollTop !== "undefined") {// 兼容IE浏览器的获取scrollTop属性scrollTop = document.body.scrollTop;}return scrollTop;}//获取可滚动高度const getScrollHeight = () => {let dom = document.getElementById("list-box");var scrollHeight = 0;if (typeof dom.scrollHeight !== "undefined") {// 如果浏览器支持直接获取scrollHeight属性scrollHeight = dom.scrollHeight;} else if (typeof dom.offsetHeight !== "undefined") {// 如果浏览器支持offsetHeight属性scrollHeight = dom.offsetHeight;} else if (typeof dom.clientHeight !== "undefined") {// 如果浏览器支持clientHeight属性scrollHeight = dom.clientHeight;}return scrollHeight;}//获取可见区域高const getClientHeight = () => {let dom = document.getElementById("list-box");var clientHeight = 0;if (typeof dom.clientHeight !== "undefined") {// 如果浏览器支持直接获取clientHeight属性clientHeight = dom.clientHeight;} else if (typeof dom.offsetHeight !== "undefined") {// 如果浏览器支持offsetHeight属性clientHeight = dom.offsetHeight;}return clientHeight;}return ({data.map((item, index) => {return (- {item}
)})}
)
}
export default Home1;
样式:
* {margin: 0;padding: 0;
}.listBox {width: 300px;height: 800px;border: 1px solid red;overflow: auto;}.listItem {width: 100%;height: 80px;border-bottom: 1px solid blue;
}
4.vue里
vue里 以上代码理论上也能使用,把函数放到 methods里 变量放到data里(vue2)。
vue3的话就按照 ref写响应式变量,const 写函数。
如果 documnet.getxx不好用可以使用 vue 里的ref ,react同理。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
