当前位置:   article > 正文

js、react、vue里滚动到底部加载数据和滚动到顶部实现(js监听滚动事件,到底部请求接口)_js滚动条到最底下请求接口

js滚动条到最底下请求接口

前言:

最近在做一个项目,一个列表展示原本是分页器,点击下一页,请求接口。但是业务说需要改成滑倒底部,加载数据。

一、实现过程

整体思路就是 获取 滚动元素的 scrollHeight(元素内容的总高度)、clientHeight(元素的可见高度)、scrollTop(元素滚动条垂直滚动的距离)

  • scrollHeight表示元素内容的总高度,包括溢出部分;
  • clientHeight表示元素的可见高度,不包括滚动条、边框和外边距;
  • scrollTop表示元素滚动条垂直滚动的距离,即内容顶部相对于可见区域顶部的偏移量。

然后 在滚动事件里 判断 满足scrollTop+clientHeight >=scrollHeight  即可调用接口。

1.html+js
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Document</title>
  8. </head>
  9. <style>
  10. /* * {
  11. padding: 0;
  12. margin: 0;
  13. } */
  14. ul>li {
  15. width: 300px;
  16. height: 100px;
  17. list-style: none;
  18. border: 1px solid red;
  19. text-align: center;
  20. }
  21. #btnTop {
  22. position: fixed;
  23. bottom: 50px;
  24. right: 50px;
  25. }
  26. </style>
  27. <body>
  28. <div class="a">
  29. <ul id="box">
  30. </ul>
  31. <div>
  32. <button id="btnTop">滚动到顶部</button>
  33. </div>
  34. </div>
  35. </body>
  36. <script>
  37. //获取滚动条被卷进去的高
  38. function getScrollTop() {
  39. var scrollTop = 0, bodyScrollTop = 0, documentScrollTop = 0;
  40. if (document.body) {
  41. bodyScrollTop = document.body.scrollTop;
  42. }
  43. if (document.documentElement) {//兼容ie
  44. documentScrollTop = document.documentElement.scrollTop;
  45. }
  46. scrollTop = (bodyScrollTop - documentScrollTop > 0) ? bodyScrollTop : documentScrollTop;
  47. return scrollTop;
  48. }
  49. //获取可滚动高度
  50. function getScrollHeight() {
  51. var scrollHeight = 0, bodyScrollHeight = 0, documentScrollHeight = 0;
  52. if (document.body) {
  53. bodyScrollHeight = document.body.scrollHeight;
  54. }
  55. if (document.documentElement) {//兼容ie
  56. documentScrollHeight = document.documentElement.scrollHeight;
  57. }
  58. scrollHeight = (bodyScrollHeight - documentScrollHeight > 0) ? bodyScrollHeight : documentScrollHeight;
  59. return scrollHeight;
  60. }
  61. //获取可见区域高
  62. function getWindowHeight() {
  63. var windowHeight = 0;
  64. if (document.compatMode == "CSS1Compat") {//兼容ie
  65. windowHeight = document.documentElement.clientHeight;
  66. } else {
  67. windowHeight = document.body.clientHeight;
  68. }
  69. return windowHeight;
  70. }
  71. function add(val) { //这里实际是请求接口比如到底部请求下一页接口
  72. let box = document.getElementById('box');
  73. for (var i = 0; i < val; i++) {
  74. let li = document.createElement('li');
  75. li.innerText = i;
  76. box.appendChild(li)
  77. }
  78. }
  79. add(10)
  80. //事件监听
  81. window.onscroll = function () {
  82. //滚动条被卷进去的高+可见区域高=可滚动高度说明到底部了
  83. console.log(getScrollTop() + getWindowHeight(), getScrollHeight())
  84. //到底部请求接口 Math.round四舍五入因为太多位会导致精度缺失
  85. if (Math.round(getScrollTop() + getWindowHeight()) >= getScrollHeight()) {
  86. add(10)
  87. }
  88. };
  89. let btn = document.getElementById('btnTop');
  90. btn.onclick = function () { // 页面滚动到顶部
  91. // 方法一
  92. document.body.scrollTop = document.documentElement.scrollTop = 0
  93. // 方法二
  94. //document.body.scrollIntoView()
  95. // scrollIntoView 是元素也有的方法, 可以用在页面元素上,例如
  96. // document.getElementById('id').scrollIntoView()
  97. }
  98. </script>
  99. </html>
2.react实现
  1. import React, { Component } from 'react';
  2. class Index extends Component {
  3. constructor(props) {
  4. super(props)
  5. this.state = {
  6. data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  7. }
  8. }
  9. componentDidMount() {
  10. window.addEventListener("scroll", this.add);//监听滚动事件
  11. }
  12. add = () => {
  13. let { data, page } = this.state;
  14. console.log(Math.round(this.getScrollTop() + this.getWindowHeight()), this.getScrollHeight())
  15. if (Math.round(this.getScrollTop() + this.getWindowHeight()) >= this.getScrollHeight() - 1) {
  16. //项目中在这里面请求接口
  17. data.push(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
  18. this.setState({
  19. data
  20. })
  21. }
  22. }
  23. //获取滚动条被卷进去的高
  24. getScrollTop = () => {
  25. var scrollTop = 0, bodyScrollTop = 0, documentScrollTop = 0;
  26. if (document.body) {
  27. bodyScrollTop = document.body.scrollTop;
  28. }
  29. if (document.documentElement) {//兼容ie
  30. documentScrollTop = document.documentElement.scrollTop;
  31. }
  32. scrollTop = (bodyScrollTop - documentScrollTop > 0) ? bodyScrollTop : documentScrollTop;
  33. return scrollTop;
  34. }
  35. //获取可滚动高度
  36. getScrollHeight = () => {
  37. var scrollHeight = 0, bodyScrollHeight = 0, documentScrollHeight = 0;
  38. if (document.body) {
  39. bodyScrollHeight = document.body.scrollHeight;
  40. }
  41. if (document.documentElement) {//兼容ie
  42. documentScrollHeight = document.documentElement.scrollHeight;
  43. }
  44. scrollHeight = (bodyScrollHeight - documentScrollHeight > 0) ? bodyScrollHeight : documentScrollHeight;
  45. return scrollHeight;
  46. }
  47. //获取可见区域高
  48. getWindowHeight = () => {
  49. var windowHeight = 0;
  50. if (document.compatMode == "CSS1Compat") {//兼容ie
  51. windowHeight = document.documentElement.clientHeight;
  52. } else {
  53. windowHeight = document.body.clientHeight;
  54. }
  55. return windowHeight;
  56. }
  57. componentWillUnmount(){
  58. window.removeEventListener("scroll",this.add);//销毁监听事件防止内存泄漏
  59. }
  60. render() {
  61. let { data } = this.state;
  62. return (
  63. <div>
  64. <ul>
  65. {
  66. data.map((item, index) => {
  67. return (
  68. <li style={{ height: "200px" }} key={index}>{item}</li>
  69. )
  70. })
  71. }
  72. </ul>
  73. </div>
  74. );
  75. }
  76. }
  77. export default Index
3.react升级版本 

 为什么升级呢,因为 我发现上一个版本不适合所有场景(基于body的)。上面的版本知识和 没有指定 滚动dom的情况。而大部分使用场景都是需要指定某个元素的。所以我做了改动,也就是这个版本更灵活。

1.class版本
  1. import React, { FC, useEffect, useRef, useState, Component } from 'react'
  2. import styles from './Home.module.less'
  3. class Home1 extends Component {
  4. constructor(props) {
  5. super(props)
  6. this.state = {
  7. data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
  8. dom: null
  9. }
  10. }
  11. componentDidMount() {
  12. let dom = document.getElementById("list-box");
  13. dom.addEventListener("scroll", this.add);//监听滚动事件
  14. this.setState({
  15. dom
  16. })
  17. }
  18. add = () => {
  19. let { data, page } = this.state;
  20. console.log(Math.round(this.getScrollTop() + this.getClientHeight()), this.getScrollHeight())
  21. if (Math.round(this.getScrollTop() + this.getClientHeight()) >= this.getScrollHeight() - 1) {
  22. //项目中在这里面请求接口
  23. let arr=[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
  24. let data1 = data.concat(arr);
  25. this.setState({
  26. data: data1
  27. })
  28. }
  29. }
  30. //获取滚动条被卷进去的高
  31. getScrollTop = () => {
  32. const { dom } = this.state;
  33. let scrollTop = 0;
  34. if (typeof dom.scrollTop !== "undefined") {
  35. // 如果浏览器支持直接获取scrollTop属性
  36. scrollTop = dom.scrollTop;
  37. } else if (typeof dom.pageYOffset !== "undefined") {
  38. // 如果浏览器支持pageYOffset属性
  39. scrollTop = dom.pageYOffset;
  40. } else if (typeof dom.scrollY !== "undefined") {
  41. // 如果浏览器支持scrollY属性
  42. scrollTop = dom.scrollY;
  43. } else if (typeof document.documentElement.scrollTop !== "undefined") {
  44. // 兼容IE浏览器的获取scrollTop属性
  45. scrollTop = document.documentElement.scrollTop;
  46. } else if (typeof document.body.scrollTop !== "undefined") {
  47. // 兼容IE浏览器的获取scrollTop属性
  48. scrollTop = document.body.scrollTop;
  49. }
  50. return scrollTop;
  51. }
  52. //获取可滚动高度
  53. getScrollHeight = () => {
  54. const { dom } = this.state;
  55. var scrollHeight = 0;
  56. if (typeof dom.scrollHeight !== "undefined") {
  57. // 如果浏览器支持直接获取scrollHeight属性
  58. scrollHeight = dom.scrollHeight;
  59. } else if (typeof dom.offsetHeight !== "undefined") {
  60. // 如果浏览器支持offsetHeight属性
  61. scrollHeight = dom.offsetHeight;
  62. } else if (typeof dom.clientHeight !== "undefined") {
  63. // 如果浏览器支持clientHeight属性
  64. scrollHeight = dom.clientHeight;
  65. }
  66. return scrollHeight;
  67. }
  68. //获取可见区域高
  69. getClientHeight = () => {
  70. const { dom } = this.state;
  71. var clientHeight = 0;
  72. if (typeof dom.clientHeight !== "undefined") {
  73. // 如果浏览器支持直接获取clientHeight属性
  74. clientHeight = dom.clientHeight;
  75. } else if (typeof dom.offsetHeight !== "undefined") {
  76. // 如果浏览器支持offsetHeight属性
  77. clientHeight = dom.offsetHeight;
  78. }
  79. return clientHeight;
  80. }
  81. componentWillUnmount() {
  82. const { dom } = this.state;
  83. dom.removeEventListener("scroll", this.add);//销毁监听事件防止内存泄漏
  84. }
  85. render() {
  86. let { data } = this.state;
  87. return (
  88. <div>
  89. <ul className={styles.listBox} id='list-box'>
  90. {
  91. data.map((item, index) => {
  92. return (
  93. <li className={styles.listItem} key={index}>{item}</li>
  94. )
  95. })
  96. }
  97. </ul>
  98. </div>
  99. );
  100. }
  101. }
  102. export default Home1;

样式:

  1. * {
  2. margin: 0;
  3. padding: 0;
  4. }
  5. .listBox {
  6. width: 300px;
  7. height: 800px;
  8. border: 1px solid red;
  9. overflow: auto;
  10. }
  11. .listItem {
  12. width: 100%;
  13. height: 80px;
  14. border-bottom: 1px solid blue;
  15. }

 

2.hook版本
  1. import React, { FC, useEffect, useRef, useState, Component } from 'react'
  2. import styles from './Home.module.less'
  3. const Home1 = () => {
  4. const [data, setData] = useState([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  5. useEffect(() => {
  6. let dom = document.getElementById("list-box");
  7. dom.addEventListener("scroll", add);//监听滚动事件
  8. return () => {
  9. // 组件卸载时,移除滚动事件监听器
  10. dom.removeEventListener('scroll', add);
  11. };
  12. }, [])
  13. const add = () => {
  14. //console.log(Math.round(getScrollTop() + getClientHeight()), getScrollHeight())
  15. if (Math.round(getScrollTop() + getClientHeight()) >= getScrollHeight()-1) {
  16. //项目中在这里面请求接口
  17. let data1 = data.push(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
  18. setData(prevData => prevData.concat(data1));
  19. }
  20. }
  21. //获取滚动条被卷进去的高
  22. const getScrollTop = () => {
  23. let dom = document.getElementById("list-box");
  24. let scrollTop = 0;
  25. if (typeof dom.scrollTop !== "undefined") {
  26. // 如果浏览器支持直接获取scrollTop属性
  27. scrollTop = dom.scrollTop;
  28. } else if (typeof dom.pageYOffset !== "undefined") {
  29. // 如果浏览器支持pageYOffset属性
  30. scrollTop = dom.pageYOffset;
  31. } else if (typeof dom.scrollY !== "undefined") {
  32. // 如果浏览器支持scrollY属性
  33. scrollTop = dom.scrollY;
  34. } else if (typeof document.documentElement.scrollTop !== "undefined") {
  35. // 兼容IE浏览器的获取scrollTop属性
  36. scrollTop = document.documentElement.scrollTop;
  37. } else if (typeof document.body.scrollTop !== "undefined") {
  38. // 兼容IE浏览器的获取scrollTop属性
  39. scrollTop = document.body.scrollTop;
  40. }
  41. return scrollTop;
  42. }
  43. //获取可滚动高度
  44. const getScrollHeight = () => {
  45. let dom = document.getElementById("list-box");
  46. var scrollHeight = 0;
  47. if (typeof dom.scrollHeight !== "undefined") {
  48. // 如果浏览器支持直接获取scrollHeight属性
  49. scrollHeight = dom.scrollHeight;
  50. } else if (typeof dom.offsetHeight !== "undefined") {
  51. // 如果浏览器支持offsetHeight属性
  52. scrollHeight = dom.offsetHeight;
  53. } else if (typeof dom.clientHeight !== "undefined") {
  54. // 如果浏览器支持clientHeight属性
  55. scrollHeight = dom.clientHeight;
  56. }
  57. return scrollHeight;
  58. }
  59. //获取可见区域高
  60. const getClientHeight = () => {
  61. let dom = document.getElementById("list-box");
  62. var clientHeight = 0;
  63. if (typeof dom.clientHeight !== "undefined") {
  64. // 如果浏览器支持直接获取clientHeight属性
  65. clientHeight = dom.clientHeight;
  66. } else if (typeof dom.offsetHeight !== "undefined") {
  67. // 如果浏览器支持offsetHeight属性
  68. clientHeight = dom.offsetHeight;
  69. }
  70. return clientHeight;
  71. }
  72. return (
  73. <div>
  74. <ul className={styles.listBox} id='list-box'>
  75. {
  76. data.map((item, index) => {
  77. return (
  78. <li className={styles.listItem} key={index}>{item}</li>
  79. )
  80. })
  81. }
  82. </ul>
  83. </div>
  84. )
  85. }
  86. export default Home1;

   样式:

  1. * {
  2. margin: 0;
  3. padding: 0;
  4. }
  5. .listBox {
  6. width: 300px;
  7. height: 800px;
  8. border: 1px solid red;
  9. overflow: auto;
  10. }
  11. .listItem {
  12. width: 100%;
  13. height: 80px;
  14. border-bottom: 1px solid blue;
  15. }
4.vue里

vue里 以上代码理论上也能使用,把函数放到 methods里 变量放到data里(vue2)。

vue3的话就按照 ref写响应式变量,const 写函数。

如果 documnet.getxx不好用可以使用 vue 里的ref ,react同理。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/700529
推荐阅读
相关标签
  

闽ICP备14008679号