赞
踩
最近在做一个项目,一个列表展示原本是分页器,点击下一页,请求接口。但是业务说需要改成滑倒底部,加载数据。
整体思路就是 获取 滚动元素的 scrollHeight(元素内容的总高度)、clientHeight(元素的可见高度)、scrollTop(元素滚动条垂直滚动的距离)
然后 在滚动事件里 判断 满足scrollTop+clientHeight >=scrollHeight 即可调用接口。
- <!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>
- 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
为什么升级呢,因为 我发现上一个版本不适合所有场景(基于body的)。上面的版本知识和 没有指定 滚动dom的情况。而大部分使用场景都是需要指定某个元素的。所以我做了改动,也就是这个版本更灵活。
- 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;
- }
- 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;
- }
vue里 以上代码理论上也能使用,把函数放到 methods里 变量放到data里(vue2)。
vue3的话就按照 ref写响应式变量,const 写函数。
如果 documnet.getxx不好用可以使用 vue 里的ref ,react同理。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。