js、react、vue里滚动到底部加载数据和滚动到顶部实现(js监听滚动事件,到底部请求接口)
前言:最近在做一个项目,一个列表展示原本是分页器,点击下一页,请求接口。但是业务说需要改成滑倒底部,加载数据。一、实现过程1.html+js<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="
·
前言:
最近在做一个项目,一个列表展示原本是分页器,点击下一页,请求接口。但是业务说需要改成滑倒底部,加载数据。
一、实现过程
整体思路就是 获取 滚动元素的 scrollHeight(元素内容的总高度)、clientHeight(元素的可见高度)、scrollTop(元素滚动条垂直滚动的距离)
- scrollHeight表示元素内容的总高度,包括溢出部分;
- clientHeight表示元素的可见高度,不包括滚动条、边框和外边距;
- scrollTop表示元素滚动条垂直滚动的距离,即内容顶部相对于可见区域顶部的偏移量。
然后 在滚动事件里 判断 满足scrollTop+clientHeight >=scrollHeight 即可调用接口。
1.html+js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
/* * {
padding: 0;
margin: 0;
} */
ul>li {
width: 300px;
height: 100px;
list-style: none;
border: 1px solid red;
text-align: center;
}
#btnTop {
position: fixed;
bottom: 50px;
right: 50px;
}
</style>
<body>
<div class="a">
<ul id="box">
</ul>
<div>
<button id="btnTop">滚动到顶部</button>
</div>
</div>
</body>
<script>
//获取滚动条被卷进去的高
function getScrollTop() {
var scrollTop = 0, bodyScrollTop = 0, documentScrollTop = 0;
if (document.body) {
bodyScrollTop = document.body.scrollTop;
}
if (document.documentElement) {//兼容ie
documentScrollTop = document.documentElement.scrollTop;
}
scrollTop = (bodyScrollTop - documentScrollTop > 0) ? bodyScrollTop : documentScrollTop;
return scrollTop;
}
//获取可滚动高度
function getScrollHeight() {
var scrollHeight = 0, bodyScrollHeight = 0, documentScrollHeight = 0;
if (document.body) {
bodyScrollHeight = document.body.scrollHeight;
}
if (document.documentElement) {//兼容ie
documentScrollHeight = document.documentElement.scrollHeight;
}
scrollHeight = (bodyScrollHeight - documentScrollHeight > 0) ? bodyScrollHeight : documentScrollHeight;
return scrollHeight;
}
//获取可见区域高
function getWindowHeight() {
var windowHeight = 0;
if (document.compatMode == "CSS1Compat") {//兼容ie
windowHeight = document.documentElement.clientHeight;
} else {
windowHeight = document.body.clientHeight;
}
return windowHeight;
}
function add(val) { //这里实际是请求接口比如到底部请求下一页接口
let box = document.getElementById('box');
for (var i = 0; i < val; i++) {
let li = document.createElement('li');
li.innerText = i;
box.appendChild(li)
}
}
add(10)
//事件监听
window.onscroll = function () {
//滚动条被卷进去的高+可见区域高=可滚动高度说明到底部了
console.log(getScrollTop() + getWindowHeight(), getScrollHeight())
//到底部请求接口 Math.round四舍五入因为太多位会导致精度缺失
if (Math.round(getScrollTop() + getWindowHeight()) >= getScrollHeight()) {
add(10)
}
};
let btn = document.getElementById('btnTop');
btn.onclick = function () { // 页面滚动到顶部
// 方法一
document.body.scrollTop = document.documentElement.scrollTop = 0
// 方法二
//document.body.scrollIntoView()
// scrollIntoView 是元素也有的方法, 可以用在页面元素上,例如
// document.getElementById('id').scrollIntoView()
}
</script>
</html>
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) {//兼容ie
documentScrollTop = 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) {//兼容ie
documentScrollHeight = document.documentElement.scrollHeight;
}
scrollHeight = (bodyScrollHeight - documentScrollHeight > 0) ? bodyScrollHeight : documentScrollHeight;
return scrollHeight;
}
//获取可见区域高
getWindowHeight = () => {
var windowHeight = 0;
if (document.compatMode == "CSS1Compat") {//兼容ie
windowHeight = document.documentElement.clientHeight;
} else {
windowHeight = document.body.clientHeight;
}
return windowHeight;
}
componentWillUnmount(){
window.removeEventListener("scroll",this.add);//销毁监听事件防止内存泄漏
}
render() {
let { data } = this.state;
return (
<div>
<ul>
{
data.map((item, index) => {
return (
<li style={{ height: "200px" }} key={index}>{item}</li>
)
})
}
</ul>
</div>
);
}
}
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 (
<div>
<ul className={styles.listBox} id='list-box'>
{
data.map((item, index) => {
return (
<li className={styles.listItem} key={index}>{item}</li>
)
})
}
</ul>
</div>
);
}
}
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 (
<div>
<ul className={styles.listBox} id='list-box'>
{
data.map((item, index) => {
return (
<li className={styles.listItem} key={index}>{item}</li>
)
})
}
</ul>
</div>
)
}
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同理。
更多推荐
已为社区贡献15条内容
所有评论(0)